How do I see the exact error causing a 500 in Vercel?
Open your Vercel Project Dashboard → select Deployments → click on the active production deployment → open the 'Runtime Logs' tab and filter by 'Errors'.
A Next.js API route returns a 500 Internal Server Error in production because an unhandled exception occurred in the server environment—most commonly a missing production environment variable, a timed-out database connection pool, or an unhandled JSON parsing exception on incoming request payloads.
Environment variables configured in .env.local on your laptop are not automatically present in production. If your route reads process.env.SECRET_KEY without a fallback, the code throws a fatal TypeError.
In serverless environments (like Vercel), each incoming request can spin up an isolated lambda. Without a connection pooler like PgBouncer, the database quickly exceeds max_connections and rejects queries.
In Next.js App Router, calling 'await request.json()' on a request without a body (e.g. a GET or empty POST) throws a SyntaxError that triggers a 500 if not caught.
import { NextRequest, NextResponse } from 'next/server';
export async function POST(req: NextRequest) {
try {
// 1. Verify environment configuration
const apiKey = process.env.SERVICE_API_KEY;
if (!apiKey) {
console.error('[CRITICAL] Missing SERVICE_API_KEY in production environment');
return NextResponse.json({ error: 'Server configuration error' }, { status: 500 });
}
// 2. Safe body parsing
let body;
try {
body = await req.json();
} catch {
return NextResponse.json({ error: 'Invalid JSON payload' }, { status: 400 });
}
// 3. Process business logic
const result = await processData(body, apiKey);
return NextResponse.json({ success: true, data: result }, { status: 200 });
} catch (error: any) {
console.error('[API_ERROR]', error);
return NextResponse.json(
{ error: 'Internal server error', message: error.message },
{ status: 500 }
);
}
}| Log Signature | Root Cause | Immediate Fix |
|---|---|---|
| DATABASE_URL undefined | Env variable not added to host | Add variable in Vercel / host dashboard and redeploy |
| remaining connection slots are reserved | Exceeded PostgreSQL connection limit | Configure PgBouncer or connection pool limit in Prisma |
| Unexpected end of JSON input | request.json() called on empty body | Wrap body parsing in try/catch and return 400 |
| Execution timed out (10s) | Slow unindexed database query | Run EXPLAIN ANALYZE and add missing index |
Wrap entire route execution in a top-level try/catch with structured error logging.
Validate required env variables at startup with Zod schema.
Ensure PrismaClient or pg pool is instantiated as a global singleton across serverless invocations.
Production Verification
A production platform running robust API routes with defensive input validation and connection pooling.
Open your Vercel Project Dashboard → select Deployments → click on the active production deployment → open the 'Runtime Logs' tab and filter by 'Errors'.
In Next.js hot-reloading (and serverless reuse), instantiating 'new PrismaClient()' on every request quickly exhausts database connection limits.
A 500 is an immediate internal application crash. A 504 indicates the handler exceeded the server's maximum execution timeout (e.g. 10s or 15s) while waiting on a query or third-party API.
If this error is blocking your release build or production pipeline, Syed Alijah Muhammad can diagnose and deploy a clean fix. Send the repository access, error trace, and platform details.