"CORS preflight failed" means the browser blocked a request before it was sent because the server rejected the OPTIONS preflight check.
What "CORS preflight failed" Means
When your browser needs to send a non-simple request (like one with custom headers or a JSON content type), it first sends an OPTIONS request to check if the server allows it. If that preflight gets a non-2xx response or missing CORS headers, you see "CORS preflight failed" in the console. The actual request never reaches the server.
Why It Happens
The two most common causes are:
-
Missing or wrong
Access-Control-Allow-Originheader on the preflight response. The server must explicitly echo back the requesting origin (or*if no credentials are used). -
Missing
Access-Control-Allow-Headers— if your request sends a custom header likeAuthorizationorContent-Type: application/json, the server must whitelist it in the preflight response.
Example Code That Triggers It
Here's a minimal Next.js API route that triggers this error when called from a browser on a different origin:
// app/api/data/route.ts
import { NextResponse } from 'next/server';
export async function OPTIONS() {
// Missing CORS headers — this causes preflight to fail
return new NextResponse(null, { status: 204 });
}
export async function POST(request: Request) {
const body = await request.json();
return NextResponse.json({ received: body });
}
Calling this from a client on http://localhost:3001 while the API runs on http://localhost:3000 fails because the preflight response has no Access-Control-Allow-Origin header.
How to Fix It
Add the required CORS headers to the OPTIONS handler:
// app/api/data/route.ts
import { NextResponse } from 'next/server';
export async function OPTIONS() {
return new NextResponse(null, {
status: 204,
headers: {
'Access-Control-Allow-Origin': 'http://localhost:3001',
'Access-Control-Allow-Methods': 'POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
},
});
}
The fix works because the browser now sees the preflight response includes the origin, methods, and headers it needs. It then proceeds with the actual POST request.
Common Mistakes That Cause This
Mistake 1: Using * with credentials. If your request includes credentials: 'include', the server can't respond with Access-Control-Allow-Origin: * — it must echo the specific origin. Browsers enforce this strictly.
Mistake 2: Only handling CORS in production. Many devs add CORS headers only in the production server config, then hit this error locally where the dev server doesn't have the same middleware. Test with the same origin setup in development.
When Should You Worry About This?
You should worry when the preflight fails in production for authenticated requests. If you're just hitting this in local development, it's almost always a missing header in your dev server config. But if it happens in production with Authorization headers, you're leaking that your CORS policy isn't configured for your actual frontend domain — fix it before users see blocked API calls.
Check your browser's Network tab first, look at the OPTIONS request's response headers, and verify Access-Control-Allow-Origin matches your frontend origin exactly.