Host accounts had been working locally for a week: sign up, confirmation email, click, dashboard. I deployed on 17 February and signed up from my phone, to see. The email never came. Not in the inbox, not in spam, not the next day.
What I believed
That a sending service was misconfigured, or a domain was not verified. That is the usual cause of emails that do not arrive, and it is the one the AI tool suggested first. I checked the Supabase configuration, which handles authentication. Everything was in order. The email was not lost in transit: it was never sent.
What it was
Three problems stacked on each other, found in order.
First, the sign-up form called Supabase without telling it where to send the user after confirmation. Without that address, no email. One line to add, emailRedirectTo, and the email went out.
Then the email went out, but the link inside was broken. It pointed to https://sync-buzzer.vercel.app%0A/auth/confirm. That %0A is a newline, URL-encoded. When I had pasted the environment variables into Vercel’s interface, I had carried a line break at the end of the value. Invisible in the UI, invisible in the logs, present in every URL built with it.
// the value contained "https://sync-buzzer.vercel.app\n"
const base = process.env.NEXT_PUBLIC_APP_URL.trim();
Finally, once the link was valid, confirmation still failed. Because production was not talking to the same database as my machine: two separate Supabase projects, created at different times, and Vercel’s variables pointed at the old one. The account was created on one side, the confirmation looked on the other.
On 17 February I added a check of the variables at server start-up, which refuses to launch the app if a value is missing or malformed. It has already stopped me twice since.
What I take from it
None of these three problems was in the code the tool had written. They were in what surrounds it: a parameter I had not asked for, a copy-paste, a configuration that had drifted. That is exactly the zone generation speed does not cover, and it is where I now spend most of my time.
The newline in particular reminded me of a rule I applied in another life: never trust a value that has passed through a clipboard. Clean it on the way in, or check it at start-up. Preferably both.
Three bugs, zero in the code. All in the space between the code and the world.
Get the journal by email
About one entry a week. What I build, what breaks, what I learn. No promotion, one-click unsubscribe.
You can also follow the RSS feed.