Skip to main content

Zod Validation Error on Startup

Symptom: The API crashes immediately with an error like:
Error: Invalid environment variables:
  - DATABASE_URL: Required
  - REDIS_URL: Required
Cause: Missing or malformed environment variables. Every env var is validated with Zod at startup. Fix:
  1. Check your .env file (local) or platform env var settings (Render/Vercel)
  2. Compare against .env.example in the relevant app directory
  3. Make sure URLs are valid (include https://) and strings aren’t empty

ENCRYPTION_KEY Validation Failure

Symptom: API crashes with:
ENCRYPTION_KEY: Must be a 64-char hex string (32 bytes)
Cause: The ENCRYPTION_KEY must be exactly 64 hexadecimal characters. Fix: Generate a valid key:
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

CORS Errors in the Browser

Symptom: API requests from the frontend fail with CORS errors in the browser console. Cause: The FRONTEND_URL env var on the API doesn’t include the frontend’s origin. Fix: Set FRONTEND_URL to match your frontend URL exactly. For multiple origins, use comma-separated values:
FRONTEND_URL=https://folksbase.joselito.dev,https://staging.folksbase.dev
Each origin must start with http://, https://, or *. (wildcard).

Render Health Check Failing

Symptom: Render shows the service as unhealthy and keeps restarting it. Cause: The /health endpoint checks both the database (Neon) and Redis connections. If either is unreachable, it returns a 503. Fix:
  1. Check that DATABASE_URL and REDIS_URL are correct in Render’s env vars
  2. Verify your Neon database is active (free tier databases pause after inactivity)
  3. Verify your Upstash Redis instance is running
  4. Check Render logs for the specific error in the health check response

Stale Schema After Database Changes

Symptom: db:push or db:migrate doesn’t detect your schema changes. Cause: Drizzle reads from dist/ (compiled JS), not src/ (TypeScript). If you run drizzle-kit directly, it reads stale compiled files. Fix: Always use the pnpm scripts — they run tsc before drizzle-kit:
# Correct
pnpm --filter @folksbase/db db:push

# Wrong — reads stale dist/
npx drizzle-kit push

Build Fails in Monorepo

Symptom: Vercel or Render build fails because a shared package can’t be found. Cause: The build command isn’t resolving monorepo dependencies correctly. Fix:
  • On Vercel: set the root directory to apps/web and let Turborepo handle dependency resolution
  • On Render: the render.yaml build command (pnpm install && pnpm --filter @folksbase/api build) handles this correctly
  • Make sure pnpm-lock.yaml is committed — both platforms use --frozen-lockfile

Neon Database Connection Timeout

Symptom: API requests hang or timeout when querying the database. Cause: The project uses Neon’s HTTP driver, which works over standard HTTPS. Connection issues are usually network-related. Fix:
  1. Check that the Neon database isn’t paused (free tier pauses after inactivity)
  2. Verify the DATABASE_URL is correct and includes the correct project/branch
  3. Check Neon’s status page for outages
  4. Remember: the HTTP driver is intentional for Render compatibility — don’t switch to the WebSocket driver

Playwright E2E Tests Failing in CI

Symptom: E2E tests pass locally but fail in CI. Cause: Usually a missing env var or the preview URL isn’t ready yet. Fix:
  1. Ensure E2E_USER_EMAIL and E2E_USER_PASSWORD are set in CI secrets (real Supabase credentials)
  2. Verify PLAYWRIGHT_BASE_URL points to the correct preview URL
  3. Check that the Vercel preview deployment finished before tests started

Existing Plaintext Keys After Enabling Encryption

Symptom: Settings with resend_api_key fail to load after deploying the encryption feature. Cause: Existing plaintext keys in the database can’t be decrypted because they were never encrypted. Fix: Either:
  • Have users re-enter their Resend API keys after deploying (simplest)
  • Run a one-time migration script to encrypt existing plaintext values