Next.js API Route 500 Error? How to Fix Route Handler Errors
Diagnose Next.js API route failures — 500 with no browser message, edge runtime Node.js errors, body parsing broken in App Router, CORS rejections, and Pages vs App Router export differences.
1. 500 Error With No Message — Check the Terminal
Next.js intentionally returns a blank 500 Internal Server Error body in production so your stack traces never leak to the browser. The actual error — with the message, file path, and line number — is always printed to the terminal running the Next.js process.
Error: Cannot read properties of undefined (reading 'id')
at GET (app/api/user/route.ts:12:22)
at async NextRequest ... - Dev server: the terminal running
next devprints the full error on every failed request — scroll up after the 500 appears in the browser. - Production (Vercel): go to Vercel dashboard → your project → Deployments → Functions tab → select the route to see per-request logs.
- Wrap handlers in try/catch: catch the error and return a
500response with the message during development to surface it in the browser network tab.
// app/api/example/route.ts
export async function GET(request: Request) {
try {
const data = await fetchSomething();
return Response.json(data);
} catch (err) {
console.error(err); // always check terminal
return Response.json(
{ error: (err as Error).message },
{ status: 500 }
);
}
} 2. "The Edge Runtime Does Not Support Node.js..." Error
This error fires when your Route Handler (or a package it imports) uses Node.js-only APIs — fs, http, Buffer, or packages like axios that depend on them — while the route is running in the Edge runtime.
// app/api/heavy/route.ts
export const runtime = 'nodejs'; // ← add this line
export async function GET() {
// fs, axios, Buffer, etc. all work here now
return Response.json({ ok: true });
} fetch() instead of axios, use the Web Crypto API instead of Node crypto.
// Before (breaks on edge)
import axios from 'axios';
const res = await axios.get('https://api.example.com/data');
// After (edge-compatible)
const res = await fetch('https://api.example.com/data');
const data = await res.json(); 3. Body Parsing: req.body is Undefined in App Router
The Pages Router (pages/api/) automatically parses the body into req.body. App Router Route Handlers (app/api/) receive a standard Web API Request — there is no req.body property. You must read the body explicitly:
// app/api/submit/route.ts
export async function POST(request: Request) {
// JSON body
const body = await request.json();
// Form data (multipart or application/x-www-form-urlencoded)
const form = await request.formData();
const name = form.get('name');
// Raw text
const text = await request.text();
return Response.json({ received: true });
} - body-parser does not apply: middleware that works with the Pages Router (like body-parser) is not compatible with App Router Route Handlers.
- Content-Type must match:
request.json()throws if the request body is not valid JSON — make sure the client setsContent-Type: application/json. - Read body only once: the Request body is a stream — calling
request.json()a second time throws body already consumed. Read it once and store the result in a variable.
4. CORS Errors From API Routes
Browsers block cross-origin requests to your API unless the response includes the correct CORS headers. In App Router, return the headers on every response and export an OPTIONS handler to answer preflight requests:
// app/api/data/route.ts
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
};
export function OPTIONS() {
return new Response(null, { status: 204, headers: corsHeaders });
}
export async function GET() {
return Response.json({ data: 'hello' }, { headers: corsHeaders });
}
To apply CORS globally across all routes without touching individual files, use next.config.js:
// next.config.js
module.exports = {
async headers() {
return [
{
source: '/api/:path*',
headers: [
{ key: 'Access-Control-Allow-Origin', value: '*' },
{ key: 'Access-Control-Allow-Methods', value: 'GET,POST,OPTIONS' },
],
},
];
},
}; 5. Pages Router vs App Router — File Names and Exports
The two routers have different file names and export conventions. Mixing them up causes routes to silently 404 or be ignored.
// Pages Router — pages/api/hello.ts
// Default export, req/res pattern
export default function handler(req, res) {
res.json({ message: 'hello' });
}
// App Router — app/api/hello/route.ts
// Named exports per HTTP method, no default export
export async function GET(request: Request) {
return Response.json({ message: 'hello' });
}
export async function POST(request: Request) {
const body = await request.json();
return Response.json({ received: body });
} - File name: Pages Router uses any file name under
pages/api/; App Router requires the file to be namedroute.ts(orroute.js) inside a directory underapp/. - Named exports only: App Router ignores a default export — exporting
export default function handlerfrom aroute.tsfile will result in a 405 Method Not Allowed. - Middleware scope: Next.js middleware (
middleware.ts) matches all routes by default. Set thematcherconfig to restrict it and avoid it running on/api/unintentionally.
Know when Vercel has an outage affecting your Next.js app
Free email alerts when Vercel or Next.js infrastructure has incidents — no credit card needed.
FAQ
Why does my Next.js API route return 500 with no error message in the browser?
Next.js hides server-side errors from the browser in production. Open the terminal running next dev or check your hosting provider's function logs — the full stack trace is always printed there.
What does "The edge runtime does not support Node.js" mean?
Your Route Handler is set to run on the Edge runtime but uses a Node.js-only package. Export export const runtime = 'nodejs' from the route file, or replace Node.js-only imports with Web API equivalents like global fetch() instead of axios.
Why is req.body undefined in App Router Route Handlers?
App Router Route Handlers receive a standard Web API Request object, not the Express-style req from Pages Router. Use await request.json() to read a JSON body.
How do I add CORS headers to a Next.js API route?
In App Router, include Access-Control-Allow-Origin in your Response headers and export an OPTIONS function for preflight. For global CORS, use the headers() function in next.config.js.