Troubleshooting
Symptom → possible causes → diagnosis → corrective action, from errors verified while building this kit. Causes are ranked by likelihood, not guarantees — read every step.
Common Errors#
Config validation error: <VARIABLE_NAME> is required
Appears in: backend terminal, at startup
- Read every variable named in the Joi message (abortEarly:false prints them all).
- Copy backend/.env.example → backend/.env and fill each one.
- Give JWT_SECRET ≥ 32 chars (not the .env.example placeholder).
- Restart manually — nodemon does not watch .env.
MongooseServerSelectionError / connection refused
Appears in: backend terminal, at startup
- Local MongoDB: is the service running? (Get-Service MongoDB / brew services list).
- Atlas: is your IP in Network Access?
- Re-test the URI host/port/name against the intended value.
- Backend connects with a 5-second server-selection timeout — a wrong port fails fast.
Google OAuth: error 400 redirect_uri_mismatch
Appears in: Google's account-picker page
- Compare the URI Google received with the client's Authorized redirect URIs in Google Console — must match character-for-character (scheme, port, path, no trailing slash).
- The same string must be in backend/.env as GOOGLE_CALLBACK_URL.
- For production add the https:// URI in the console; keep localhost entries as well.
Google OAuth: Access blocked · 403 access_denied
Appears in: Google's consent screen
- The consent screen is in Testing status and the account is not a test user → add it under Test users.
- Or publish the app when production-ready.
- Workspace-managed accounts may be blocked by their admin.
Google OAuth: invalid_client
Appears in: backend terminal during callback
- Client ID or Secret copied incompletely → copy both again from Credential details.
- Careful: quotes or spaces break the values — they belong on a single raw line.
Google OAuth: invalid_grant · Missing code verifier
Appears in: backend terminal during callback
- PKCE verifier missing at the token exchange. The shipped code already resolves this by passing codeVerifier (camelCase) to google-auth-library getToken(); if you changed that call, note that snake_case code_verifier is silently ignored by the library — restore the camelCase property.
Backend log: “Google OAuth is not configured …”
Appears in: backend terminal
- GOOGLE_CLIENT_ID and GOOGLE_CALLBACK_URL (and the secret) are missing/empty → fill the trio from the Google OAuth guide and restart.
429 Too Many Requests while testing OTP
Appears in: forgot-password / verify-otp endpoints
- Working as designed: 3 code requests per email per 15 min, plus 10 auth attempts per IP.
- Development shortcut: raise RATE_LIMIT_*_MAX_REQUESTS in backend/.env.
- Wait out the window otherwise; a restart of the backend does NOT clear in-memory counters.
Resend delivery failed / “[FAIL]” from pnpm test:email
Appears in: running pnpm test:email
- RESEND_API_KEY is missing, revoked or from another account → create a new key.
- RESEND_FROM must use a domain verified in Resend; onboarding@resend.dev can only email the account owner.
- Read the exact status printed by the script (invalid_api_key, validation_error, invalid_from_address).
- Restart the backend after editing .env — nodemon does not watch .env.
Login works but /dashboard redirects to /login
Appears in: browser after login
- Cookies fail to attach on a different site — keep backend localhost:5000 and frontend localhost:3000 during development (both same-site).
- Check that NEXT_PUBLIC_API_URL includes /api/v1.
- Never mix http:// and https:// between the two in dev.
Frontend requests 404 but the backend is running
Appears in: browser network tab
- The proxy strips /api/v1 — NEXT_PUBLIC_API_URL must include it (http://localhost:5000/api/v1).
- Restart the frontend dev server after changing .env.local.
- Probe the health endpoint directly: curl http://localhost:5000/api/v1/health.
changed .env but nothing changed
Appears in: either server
- nodemon watches JS files only; Next.js reads env at startup. Manual restart for both: Ctrl+C → pnpm dev.
PORT 5000 already in use
Appears in: backend terminal
- An older backend process still holds the port. Close the stale terminal or kill the PID (Windows: Get-NetTCPConnection -LocalPort 5000 → Stop-Process -Id <pid>), then start again.
CORS policy blocked by browser
Appears in: browser console when calling the API
- FRONTEND_URL on the backend must equal the browser origin EXACTLY (no trailing slash, matching http/https + port).
- credentials: true on the frontend matters — RTK Query baseApi already sets credentials: 'include'.
- Do not fudge by disabling CORS middleware.
Next build fails after edits
Appears in: frontend terminal
- Read the first TypeScript error — later errors are usually its consequences.
- Run pnpm build again after fixes.
- New .tsx files need valid component imports (all tools in this kit use an explicit "use client" boundary where hooks are used).
Universal Diagnosis Order#
When the exact error is unclear, diagnose in this order: (1) backend terminal logs — startup issues appear here before the browser shows anything meaningful; (2) curl http://localhost:5000/api/v1/health — success:true proves config + database load; (3) the browser network tab — inspect the failed request's URL, status, CORS headers and whether cookies were sent; (4) restart both servers after every suspicious change — most “nothing works” cases are stale processes; (5) remember 429 responses carry RateLimit headers saying exactly when the window resets — no guessing needed.
Debug Tools Shipped#
pnpm test:email you@example.com # Resend API + one test message
node seed-admin.js # create/promote the admin account
curl http://localhost:5000/api/v1/healthGoogle OAuth failures always print a dedicated “GOOGLE OAUTH ERROR” block in the backend console with Google's raw error description — copy the whole block when asking for support. The main auth/user/admin service methods log through pino with context.