All posts
corshttpdebugging

CORS preflight failed — What It Means and How to Fix It

"CORS preflight failed" explained — why it happens, a real code example that triggers it, and the exact fix.

SR

Suhail Roushan

August 6, 2026

·
3 min read
·
0 views

"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:

  1. Missing or wrong Access-Control-Allow-Origin header on the preflight response. The server must explicitly echo back the requesting origin (or * if no credentials are used).

  2. Missing Access-Control-Allow-Headers — if your request sends a custom header like Authorization or Content-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.

Related posts

Written by Suhail Roushan — Full-stack developer. More posts on AI, Next.js, and building products at suhailroushan.com/blog.

Get in touch