Supabase Auth flow_state_not_found or flow_state_expired
Supabase sign-in fails with flow_state_not_found or flow_state_expired? The PKCE login expired or was already used. Start the sign-in again in the same browser.
Reviewed October 25, 2026
What it means in plain English
Supabase's Auth error codes page lists two related codes:
flow_state_expired: the PKCE flow state that the request relates to has expired. Ask the user to sign in again.flow_state_not_found: the PKCE flow state no longer exists. Flow states expire after a while and are cleaned up. Retried requests can also cause it, because the earlier request likely used up the flow state. Ask the user to sign in again.
PKCE is the login flow where Supabase sends the user back to your app with ?code=... in the URL, and your app calls exchangeCodeForSession(code). Supabase's PKCE guide says the code is valid for 5 minutes and can be exchanged only once. After that you must restart the sign-in from scratch.
Likely causes
- The user clicked the email link or finished the OAuth sign-in more than 5 minutes after it started.
- Your callback page exchanged the code twice, for example a retry, a page reload, or code that runs the exchange more than once. The second exchange fails.
- The link was opened in a different browser or device. Supabase says the code verifier is stored locally when the flow starts, so the exchange must happen on the same browser and device.
- Two sign-ins were started in the same browser before either finished, for example
signInWithOAuth()in two tabs. Supabase says the later flow overwrites the earlier flow's code verifier, so the first one fails.
How to fix it, step by step
- Read
error.codein your app. Supabase says to useerror.codeanderror.name, not string matching on the message. - When the code is
flow_state_expiredorflow_state_not_found, show a message and send the user back to sign in again. Supabase's own guidance for both codes is to ask the user to sign in again. - Make sure your callback route calls
exchangeCodeForSession(code)once per sign-in. Do not retry it automatically with the same code. - Tell users to open the email link in the same browser where they asked for it.
- If users start sign-in in more than one tab, Supabase has an experimental option,
appendPkceFlowIdToRedirects. It adds ansb_flow_idparameter to the redirect so you can pass the right flow toexchangeCodeForSession(code, { flowId }). Supabase says this option is experimental and its API may change without notice.
How to check it worked
- A fresh sign-in, finished within a few minutes in the same browser, lands the user signed in.
- Reloading the callback page does not trigger a second code exchange.
- Your app shows a clear "please sign in again" message instead of a blank error when the code has expired.
Sources
Related fixes
More Supabase auth and email fixes
Keep going on your own.
The guides stay free. A deep leak report is $15. Fix packs are $24, or $49 for all three. There is no done-for-you repair.