AuthSessionMissingError: Auth session missing! (Supabase Auth)
Filed under Supabase & databases
Your code asked Supabase for the signed-in user in a place where no session is stored — the call ran too early, on the wrong client, or with nobody signed in.
Fastest route
Give your AI this prompt
Copy it, replace the bracketed part with your error, and send it.
Preview the prompt
I am using Supabase Auth and getting "AuthSessionMissingError: Auth session missing!" The call that throws is [getUser() / exchangeCodeForSession() / other] in this file: [paste the file or function]. This code runs in [the browser / a Next.js server component / an API route — or say "I'm not sure"]. Please: 1) search the project for every place a Supabase client is created and tell me if there is more than one, or if a plain @supabase/supabase-js client is being used on the server instead of the @supabase/ssr cookie-based client, 2) check whether the failing call can run before sign-in completes or with nobody signed in, and guard it with a getSession() check that handles the signed-out case gracefully instead of throwing, 3) if this is an OAuth or magic-link callback, make sure the code exchange completes before anything asks for the user. Constraints: do not fix this by catching the error and ignoring it, do not create a new separate client as the solution, and do not put the service role key in browser code. Make one change at a time and explain how I can test each one.
Fix it yourself
Follow the repair
- Find the exact call that throws. The stack trace or your logs will point to a line calling
getUser()orexchangeCodeForSession(). Note which file it is and where that file runs — browser, server component, or API route — because the right fix depends entirely on which side of that line the code lives. Errors that appear only sometimes are usually the "too early" kind: the call races the sign-in and loses when the network is slow. - Ask for the session before asking for the user.
getSession()does not throw when nobody is signed in — it calmly returns null. Use it as the gate, and only callgetUser()once a session exists:
This one change converts a crash into a normal, handleable state — and half the occurrences of this error are really just an app that never decided what "signed out" should look like.const { data: { session } } = await supabase.auth.getSession(); if (!session) { // Nobody is signed in here — show a login prompt or return early return null; } const { data: { user } } = await supabase.auth.getUser(); - Use one shared client, created the right way for its environment. Search the project for every
createClientcall. In the browser, there should be a single shared client (in Next.js, thecreateBrowserClientfrom@supabase/ssr, kept in one helper file that everything imports). On the server — route handlers, server components, server actions — usecreateServerClientfrom@supabase/ssrwired to the request's cookies. A plain@supabase/supabase-jsclient on the server has no access to the visitor's cookies and will report a missing session for every single visitor. - Check the client options where the session gets lost. If a client is created with custom auth options, look for
persistSession: falseor a custom storage setting pointing somewhere temporary. In the browser the defaults are what you want: the session persists across page loads and the client detects it automatically. Only change those defaults if you know exactly why. - If it happens during OAuth or email-link login, complete the exchange first. When a user returns from a Google login or a magic link, the session does not exist until the code in the URL has been exchanged for one. That exchange belongs in the callback route, and nothing that needs a user should run before it finishes:
If// In your auth callback route const code = searchParams.get("code"); if (code) { const { error } = await supabase.auth.exchangeCodeForSession(code); if (!error) redirect("/dashboard"); }exchangeCodeForSessionitself throws "session missing", the code was already used, expired, or the callback is being hit without one — send the user back to login with a friendly message instead of letting it crash. - Wait for auth to be ready before running protected code. In browser apps, gate the first user-dependent work on the auth state instead of firing it on page load: run it inside an
onAuthStateChangelistener, or after an explicit session check completes. Then test the real sequence — fresh browser, sign in, land on the page that used to crash — plus the signed-out sequence, opening the same page with no login at all. Both paths should now behave: one shows the user's data, the other shows a login prompt, and neither throws.
Why this happensOptional explanation
A Supabase session is the stored proof that a user signed in: an access token plus a refresh token, kept somewhere your client can reach — browser storage for a browser client, cookies for a server client built with @supabase/ssr. Some auth methods assume that proof exists. Ask the client for the current user with getUser(), or try to trade an OAuth login code for a session with exchangeCodeForSession(), in a place where nothing was ever stored, and instead of a polite "nobody is signed in" you get this error thrown at you.
Modern AI-built apps hit it in a few predictable spots. Code runs too early: a component or function calls getUser() on first render, before the sign-in (or the OAuth redirect coming back) has finished writing the session. Or there are two clients: the app creates one Supabase client for signing in and a different one somewhere else — a helper file, a server route using the plain @supabase/supabase-js client — and the second client has its own empty storage, so from its point of view nobody ever logged in. The server version is common in Next.js: a route handler or server component builds a client that cannot read the request's cookies, so the visitor's perfectly good session, sitting in their browser, is invisible to it.
- Too early: the call happens before sign-in (or the OAuth code exchange) completes, so no session exists yet.
- Wrong client: a second client instance with separate storage, or the plain JS client used on the server where a cookie-based client belongs.
- Persistence off: a client created with
persistSession: falseforgets the session the moment it is made. - Expecting a user who never signed in: calling
getUser()on a public page or an API route anyone can hit, where "signed out" is a normal state the code never planned for.
Quick answers
Why does getUser() throw this but getSession() does not?
getUser() assumes a session exists and throws when there is none, while getSession() simply returns null. Code that checks the session first can handle signed-out visitors as a normal case instead of a crash.
Does this mean my login is broken?
Almost always, yes. It appears after login when the code that runs next uses a different client instance, runs on the server without reading cookies, or fires before the OAuth callback has exchanged the login code for a session. The login worked; the follow-up code is looking for the session in the wrong place.
I only get it in server components or API routes. Same fix?
The message is the same, but the cause is different timing: on the server (especially Next.js with @supabase/ssr) the client could not read the visitor's cookies, so it saw no session. Use the server client wired to the request cookies, and make sure middleware is refreshing the session.