Troubleshooting
Diagnose setup, SSR, authentication, realtime, and upload failures from the boundary inward.
Start with the first boundary that fails. Avoid changing several options at once; that hides the cause.
Module cannot find Convex
Symptom: setup fails with a missing Convex URL, or queries never connect.
- Confirm
NUXT_PUBLIC_CONVEX_URLexists in the environment running Nuxt. - Confirm it points to the intended
.convex.clouddeployment. - Restart Nuxt after changing local environment files.
- If the value was added only after a production build, use Nuxt's
NUXT_PUBLIC_*runtime override or rebuild.
SSR succeeds but hydration changes the page
Symptom: initial HTML and the hydrated client show different identity or query data.
- Do not read browser-only state during server rendering.
- Pass explicit, deterministic query arguments.
- Keep the same query auth mode on server and client.
- Use
useConvexQueryinstead of manually combining a server fetch and a separate client subscription. - Check the structured query
statusanderrorinstead of treating empty data as loading.
Auth proxy fails
Symptom: sign-in returns a proxy or token-exchange error.
Check, in order:
convex.siteUrlorNUXT_PUBLIC_CONVEX_SITE_URLtargets the correct HTTP Actions origin.- Better Auth routes are registered in
convex/http.ts. - Convex has
SITE_URLset to the exact Nuxt origin. - Convex has a strong
BETTER_AUTH_SECRET. - The deployment preserves the
/api/auth/*Nitro route. - No proxy or CDN rewrites the host, cookies, request bytes, or redirect behavior unexpectedly.
A protected query runs anonymously
auth: 'optional' waits for initial auth settlement but permits anonymous execution. Use auth: 'required' when the call must not run without identity, and still enforce identity inside the Convex handler.
Use auth: 'none' only for intentionally public data. It always uses the dedicated anonymous transport, even while the user is signed in.
Realtime stops updating
- Verify
subscribewas not set tofalse. - Inspect connection state.
- Check that CSP and the network permit the exact Convex WebSocket origin.
- Confirm the component still owns the query; subscriptions stop after the last owner leaves.
- Do not construct a separate raw
ConvexClientfor the same state.
Errors lose useful detail
Use ConvexCallError fields—kind, code, status, and data—rather than parsing message strings. Run unknown failures through normalizeConvexError. The library intentionally does not expose raw upstream bodies or serialize cause.
Uploads stall
Check file limits before requesting an upload URL, confirm the generated URL has not expired, and watch queue concurrency. A successful storage upload does not automatically create an application record; treat those as two explicit steps and define compensation for the second step failing.
For a minimal reproduction, disable auth only if the failure is unrelated to identity, reduce the page to one explicit query or call, and record the public structured error. Never attach session cookies, bearer tokens, or secrets to an issue.