Troubleshooting
Symptom → cause → fix, for the problems people actually hit.
Signing in
“That sign-in link is invalid or has expired” (admin)
- Your production URL isn’t in Supabase’s allow-list. Add
https://your-app.example.com/auth/callbackunder Authentication → URL Configuration → Redirect URLs. - Admin sign-in links only go to invited team members — an unknown address gets the same “check your inbox” message but no email, by design.
No email ever arrives
RESEND_API_KEYisn’t set — mail is being logged to the server console instead of sent (in local dev, that console is where portal sign-in links live). See Environment variables.- Key set but still nothing in production: check
EMAIL_FROM— without it the sandbox sender only delivers to the Resend account owner.
The admin shows “You’re signed in as a speaker”
Your browser holds a speaker-portal session (you opened a portal link — the demo token does this). Click Leave speaker mode to clear it and return to the admin.
Files and uploads
Uploads fail on a fresh deployment
- The storage buckets don’t exist yet — run
pnpm tsx scripts/setup-storage.tsonce per environment. DIRECT_URLorSUPABASE_SERVICE_ROLE_KEYis missing — both are validated on the upload path even when the rest of the app works.
Public pages and embeds
The schedule embed or feed is empty
- Only sessions that are published and scheduled (start and end time set) appear publicly. Check the agenda’s publish toggle and the unscheduled tray.
- A saved embed that’s been disabled returns 404 on purpose — re-enable it under Widgets & Embeds.
- Changes can take up to ~5 minutes to appear on embeds (~1 minute on feeds).
Scheduled jobs
Airtable stopped syncing / reminders stopped sending in production
CRON_SECRETis unset — in production the cron endpoints answer 401 and the jobs silently stop. Set it on the project; Vercel then authenticates its own cron calls automatically.- For Airtable specifically: check Settings → Airtable — a Reconnect needed badge means the stored grant expired or
ENCRYPTION_KEYchanged, and the run log there reportsnot_configuredevents.
Things that are by design
- Accepting a proposal doesn’t email the speaker. Decision emails are always sent deliberately from Communications.
- Speakers can’t see scores or the shortlist. The portal shows shortlisted and unreviewed proposals identically as “Under review”.
- CFP drafts live on the speaker’s device. They aren’t synced to the server, so organizers can’t see them and another browser won’t have them.
- The speaker portal serves one event — the deployment’s original event. Multi-event support in the portal is on the roadmap.
- The demo portal token expires 7 days after seeding — re-run
pnpm db:seed. - Disconnecting Airtable is permanent-until-reconnected: the event won’t silently fall back to the deployment-wide
AIRTABLE_*variables.
Still stuck?
Open an issue on GitHub with the symptom, what you expected, and any server log lines (they’re prefixed — [email:mocked], [airtable], [cron:…] — and never contain full recipient addresses).