ryer.io

Soft-Deleted Users Break Re-registration

TL;DR

  • Re-registering with a previously soft-deleted email returned a 500 and dumped the user back to onboarding.
  • The backend’s register endpoint never checked for soft-deleted records, so it tried to create a duplicate.
  • The database rejected it with a duplicate key error, surfacing as an unhandled 500.
  • Fixed by setting isExistingUser from the soft-deletion state rather than from existence alone.
  • Register now returns 200, though post-registration navigation still needs work.

Testing re-registration on iOS with my own gus@ryer.io address, the app cycled back to the onboarding screen and threw a 500.

What was happening

We soft-delete users — the record stays in the database with a deleted flag rather than being removed. The register endpoint didn’t account for that. It checked whether a user existed, found nothing matching its criteria, and tried to create a new one. The database still held the original row, so it rejected the insert with a duplicate key error.

That surfaced as an unhandled 500, which is the honest description: the backend had no branch for this case at all.

The frontend made it worse. On signup failure, the Auth0 prompt backgrounded the app and the user was signed out with no feedback explaining anything. Checking the auth context showed the state changes were correct — it was navigation that failed, because it was reacting to backend logic nobody had handled.

The fix

Backend: set the isExistingUser field based on the soft-deletion state rather than on a plain existence check. A soft-deleted user is an existing user for registration purposes, and treating them as absent is what caused the collision.

Error handling: tell the user something actionable. Someone whose account was soft-deleted should be pointed at a normal sign-in rather than left staring at onboarding.

Frontend: cleaned up the state transition logic so device storage and initialisation reflect reality when navigating after registration.

Result

The register endpoint returns 200 and the user check flow behaves correctly.

Navigation after successful registration still needs debugging — registration succeeds and the transition doesn’t follow through. That’s the same post-auth navigation problem I’ve hit elsewhere today, so it’s likely one cause rather than several.

The broader point: soft deletion is a reasonable pattern, but every query that asks “does this user exist” has to decide what soft-deleted means for its particular question. Register and sign-in want different answers, and we’d only ever written one.