Missing Environment Variables
Symptoms: App crashes on startup, database connection errors, auth failures, or blank pages.
- Verify all required variables are set (see Deployment for the full list).
- Check variable names for typos — they are case-sensitive.
- Ensure
NEXT_PUBLIC_*variables are set in the deployment platform (Vercel, Docker, K8s). These are embedded at build time. - Restart the application after adding or changing variables.
Database Connection Errors
Symptoms: ECONNREFUSED, ENOTFOUND, authentication errors, or "database not found".
- Verify
TURSO_DATABASE_URLis correct (libsql://your-db-name-your-org.turso.io). - Check that
TURSO_AUTH_TOKENis valid and has not expired. - Confirm the database exists:
turso db list. - Test connectivity directly:
turso db shell your-db-name. - Check network and firewall rules if the app runs behind a NAT or VPN.
- For local file databases (
file:local.db): ensure the directory has write permissions.
Webhook Signature Validation Failures
Symptoms: Stripe or LemonSqueezy webhooks return 401 or 403.
- Verify that
STRIPE_WEBHOOK_SECRET(orLEMONSQUEEZY_WEBHOOK_SECRET) matches the signing secret shown in the provider dashboard — not the API key. - Confirm the webhook URL is correct:
- Stripe:
https://app.example.com/api/webhooks/stripe - LemonSqueezy:
https://app.example.com/api/webhooks/lemonsqueezy
- Stripe:
- Check the provider dashboard for recent delivery attempts and response codes.
- Make sure the webhook endpoint is publicly accessible and not behind authentication.
- Use the provider's webhook testing tool to send a test event.
OAuth Redirect URL Mismatch
Symptoms: OAuth login fails with "redirect_uri_mismatch" or similar error.
- Verify
BETTER_AUTH_URL(orKINDE_SITE_URL) matches your production domain exactly, including the protocol. - Add the correct redirect URLs in each OAuth provider's dashboard:
- Google:
https://app.example.com/api/auth/callback/google - GitHub:
https://app.example.com/api/auth/callback/github
- Google:
- Ensure URLs use
https://in production (nothttp://). - Wait a few minutes for OAuth provider changes to propagate.
File Upload Failures
Symptoms: Uploads fail with 500 errors, or uploaded files are not accessible.
- Verify
STORAGE_PROVIDERis set correctly (s3orr2for production). - Check S3/R2 credentials, bucket name, region, and endpoint.
- Ensure the bucket has the correct CORS policy:
[ { "AllowedOrigins": ["https://app.example.com"], "AllowedMethods": ["GET", "PUT", "POST"], "AllowedHeaders": ["*"] } ] - Verify bucket permissions allow read and write access.
- Set
S3_PUBLIC_URLif files need to be publicly accessible. - For local storage: ensure the upload directory exists and is writable by the application process.
Background Jobs Not Processing
Symptoms: Jobs are queued but never execute. Emails not sent. Scheduled tasks not running.
- Verify
JOB_PROVIDER=bullmq— thememoryprovider is for development only and does not persist across restarts. - Check that
REDIS_URLis correct and Redis is reachable. - Test the Redis connection:
redis-cli -u $REDIS_URL ping(should returnPONG). - Ensure worker processes are running (if using separate workers in Kubernetes).
- Inspect the queue:
redis-cli -u $REDIS_URL LLEN bull:codapult:wait. - Check application logs for job processing errors.
Rate Limiting Issues
Symptoms: Legitimate requests are blocked with 429, or rate limiting is not applied at all.
- For multi-instance deployments, use a Redis-backed rate limiter so limits are shared across instances.
- Verify
REDIS_URLis set (if using Redis-backed limiter). - Check the rate limit configuration in the relevant API route or
src/lib/rate-limit.ts. - Inspect response headers:
X-RateLimit-RemainingandRetry-After. - Adjust limits based on your traffic patterns.
Health Check Failures
Symptoms: Load balancer marks instances as unhealthy. Containers restart repeatedly.
- Verify the
/api/healthendpoint responds with200:curl -s http://localhost:3000/api/health - Ensure the health check path in your load balancer or orchestration platform matches
/api/health. - Confirm the health check does not require authentication.
- Verify the container is listening on port 3000.
- Check application logs for startup errors.
Build Failures
Symptoms: Deployment fails during the build step. CI/CD pipeline errors.
- Confirm the Node.js version matches (22.x recommended).
- Ensure
pnpm-lock.yamlis committed to the repository. - Verify all dependencies are installable:
pnpm install --frozen-lockfile. - Review build logs for specific TypeScript or Next.js errors.
- Test the build locally:
pnpm run build. - If the build runs out of memory, increase the Node.js heap size:
NODE_OPTIONS="--max-old-space-size=4096" pnpm run build
CORS Errors
Symptoms: Browser console shows "Access to fetch has been blocked by CORS policy".
- Verify
NEXT_PUBLIC_APP_URLmatches the domain making requests. - Check that API routes allow the correct origin.
- Review CORS configuration in
next.config.tsor Next.js middleware. - Ensure preflight (OPTIONS) requests are handled correctly.
SSL Certificate Issues
Symptoms: Browser shows SSL warnings, "certificate not found", or "ERR_CERT_AUTHORITY_INVALID".
- Verify DNS records point to the correct IP or load balancer.
- Wait for DNS propagation (can take up to 48 hours).
- Check certificate status in your provider dashboard (Vercel, ACM, Let's Encrypt).
- Ensure the certificate covers all required domains (including
www.if used). - Confirm the certificate has not expired.
Getting Help
If the issue is not covered above:
- Check application logs (Vercel dashboard, CloudWatch,
kubectl logs). - Review error details in Sentry (if configured).
- Reproduce the issue locally with production environment variables.
- Consult the Next.js docs or Turso docs.
- Open an issue in the Codapult repository.