Auth Errors
redirect_uri_mismatch
Cause: The GitHub App’s OAuth callback URL doesn’t match NEXT_PUBLIC_APP_URL + '/api/auth'.
Fix: Go to your GitHub App settings → OAuth → Callback URL. Set it to exactly:
http://localhost:3000/api/authFor production, use your actual domain. The match is exact — protocol, port, and path all matter.
state mismatch or CSRF error
Cause: The gh_auth_csrf cookie expired (10-minute limit) or was cleared before the callback.
Fix: Restart the OAuth flow from /api/auth/start. Do not navigate away or wait too long between starting the flow and completing it.
bad_verification_code
Cause: The OAuth authorization code is single-use and expires in approximately 10 minutes. It was already consumed or expired.
Fix: Retry sign-in from the beginning.
Sign-in lands on /account?authError=auth_failed
Cause: An exception was thrown in the OAuth callback (/api/auth). Sign-in no longer fails merely because installation discovery fails — listing/syncing installations is best-effort — so a remaining auth_failed points at the token exchange, the GitHub profile lookup, or session creation (e.g. a Supabase outage, or a misconfigured AUTH_SESSION_SECRET / TOKEN_ENCRYPTION_KEY).
Fix: Check server logs for [auth/callback] Error:. Verify Supabase connectivity and that the encryption/session secrets are set, then retry from /api/auth/start.
session not found after sign-in
Three possible causes:
Cause 1: Supabase migrations not applied.
npx supabase migration list # check what's applied
npx supabase db push # apply pending migrationsCause 2: SUPABASE_SERVICE_ROLE_KEY is wrong.
Check Supabase Project Settings → API → find the service_role key. It is different from the anon key.
Cause 3: NEXT_PUBLIC_SUPABASE_URL mismatch.
Verify the URL exactly matches your Supabase project URL.
401 on API requests
Cause: Session expired (24-hour TTL) or the gh_session cookie is not being sent.
Fix: Sign in again. Check that gh_session is present in DevTools → Application → Cookies for your domain.
installation not found
Cause: The GitHub App is not installed on the organization, or the installation flow did not complete.
Fix: Go to /api/install/start and complete the install flow.
Installation visible on GitHub but not in the app
Cause: The install callback (/api/install/callback) may not have run, so session_installations was never populated.
Fix: Either re-run the installation flow, or send:
POST /api/install/complete
{ "installationId": <N> }Missing GitHub App permissions banner in a workspace
Cause: The GitHub App installation for that organization is missing one or more required permissions (Metadata, Contents, Pull requests, Issues, or organization Members — all Read). This commonly happens when the app started requesting a permission after the org installed it, so an owner must approve the new request.
Fix: An org admin opens the installation settings on GitHub (the banner’s “Review permissions on GitHub” link) and approves the requested permissions. The banner reads granted permissions live from GitHub, so it clears shortly after approval.
Database Errors
insert or update on table signals violates foreign key constraint
Cause: A signal references a user or repository that doesn’t exist in the users or repositories table yet.
Fix: This should not happen in normal operation — upsertSignals() calls ensureUsersExist() automatically. If you see this during manual data operations, upsert the user/repo records first.
new row violates check constraint tokens_encrypted
Cause: Attempting to insert an auth_sessions row with tokens_encrypted = false. The check constraint requires tokens to be encrypted before storage.
Fix: This indicates a bug in the crypto path. Tokens must go through lib/auth/server/crypto.ts before being stored. Check that the encryption step is not being bypassed.
Signals going to the default partition
Cause: ensure_signals_monthly_partitions() was not called before the upsert, or the event_timestamp is outside the range covered by existing partitions.
Check:
SELECT * FROM signals_partition_health;A non-zero default_partition_row_count confirms the issue.
Fix: upsertSignals() calls the ensure_signals_monthly_partitions RPC automatically — but only when there are signals to insert. If you are inserting manually, call the RPC first.
Build and Runtime Errors
Cannot read properties of undefined on env access
Cause: Env validation is skipped in production (skipValidation: true). A required env var is missing and the code crashes when it tries to use it.
Fix: Check that every required env var is set in the Vercel dashboard under Settings → Environment Variables. There is no build-time warning for missing vars in production.
Timeout on leaderboard requests
Cause: The score and recompute routes have maxDuration = 300, which requires Vercel Pro. On the Hobby plan, the maximum is 60 seconds.
Fix: Upgrade to Vercel Pro, or reduce the scope of the leaderboard request (smaller org, narrower time range).
API rate limit exceeded during leaderboard ingest
Cause: GitHub API rate limit hit (5,000 requests/hour for user tokens; 15,000 for installation tokens).
Fix: Wait for the cooldown to expire. The 24-hour ingest cooldown should prevent most cases. Prefer installation-authenticated requests — they have higher limits.