Back to News & Insights
Web Development August 13, 2026 · 7 min read

You Know What's Worse Than Not Being Able to Log In?

This is a submission for DEV's Summer Bug Smash: Smash Stories powered by Sentry. You Know What's...

You Know What's Worse Than Not Being Able to Log In?

This is a submission for DEV's Summer Bug Smash: Smash Stories powered by Sentry.

Being told everything worked right up until you try to actually use your account.

And, somehow, I ended up being pulled into another authentication mystery. At this point, I’m starting to think authentication bugs have a personal grudge against me. 😅

In my previous Smash Story, I wrote about a bug where users simply couldn't log in. This time, the problem was sneakier because most of the flow looked completely healthy. The user was approved, the background task ran, the email and SMS arrived, and Cognito had a user.

The authentication setup was fairly large and had evolved over time, so there wasn't one shiny User Pool doing everything.

We had an older Cognito User Pool supporting existing authentication flows, including mobile-based signup, while a newer User Pool handled a newer flow where users received an email containing their PIN. Both pools were intentional because they supported different parts of the authentication journey.

The interesting part was that the application database had its own representation of a user, while Cognito had another. On top of that, some of the work connecting those two systems happened asynchronously.

A member could create a partner or dependant during signup or later from the member details area. A relevant non-member user would then approve the account, which scheduled an asynchronous task called SendingEmailsAfterApprovalBot in a TaskList database table.

That task ran every 15 minutes, and once it executed, the partner or dependant received an email and SMS containing a code. They could then confirm their account, set a password and sign in.

A partner gets approved at 10:01 AM, so the background task is scheduled and everyone moves on with their lives. At 10:05 AM, before the task has run, the partner changes their name.

That tiny change matters because the username for partner and dependant accounts is derived from their details. The database now has the new username, while Cognito may still know about the old username.

The task is still waiting patiently in the database, completely unaware that the identity it is about to process has changed underneath it.

The background task tries to create the Cognito user using the latest username stored in the database.

Cognito rejects the creation because the email address is already associated with an existing user, but that user has a different username.

So we weren't dealing with a simple "just update the username" situation. We had two systems describing the same person with different usernames, and Cognito was quite reasonably refusing to create another user with the same email.

The user could still receive the expected email and SMS. There was no obvious failure screaming for attention. The asynchronous task had run, notifications had gone out and Cognito already had a user associated with the email.

So the user did what any reasonable person would do: they followed the instructions.

They entered their code, tried to confirm their account and attempted to set their password.

Want to discuss this further?

Book a free strategy call with our team to see how these insights apply to your specific business goals.

Book a consultation