---
name: debug-cors-errors
description: Diagnoses and fixes CORS errors such as "No 'Access-Control-Allow-Origin' header" or failed preflight OPTIONS requests between a frontend and an API. Use when the browser console says blocked by CORS policy, fetch fails only in the browser, or cookies are not sent cross-origin.
license: CC-BY-4.0
metadata:
  category: debugging
  tags: "cors,http,api,browser"
  author: johnny-bravo
  version: "1.0"
  updated: "2026-10-30"
  status: published
---

# Debug CORS errors

## When to use
- A request works in curl/Postman but the browser blocks it with a CORS message.

## Steps
1. Read the exact console message and open the Network tab; find the failing request **and** any `OPTIONS` preflight before it.
2. Confirm it really is cross-origin: scheme + host + port must all match to be same-origin (`localhost:3000` vs `localhost:8000` is cross-origin).
3. Fix on the **server** (the API), not the frontend:
   - Respond to `OPTIONS` with 204 and `Access-Control-Allow-Origin: <exact origin>`, `Access-Control-Allow-Methods`, `Access-Control-Allow-Headers` (include `Content-Type`, `Authorization`).
   - Send `Access-Control-Allow-Origin` on the actual response too, including error responses.
4. For cookies/auth: client `credentials: "include"`; server `Access-Control-Allow-Credentials: true` and a specific origin (not `*`); cookies need `SameSite=None; Secure`.
5. In dev, a simpler fix is a same-origin proxy (Vite `server.proxy`, Next.js rewrites).
6. Re-test and check the preflight now returns 2xx with the headers.

## Gotchas
- A 500 or 404 without CORS headers shows up as a CORS error; check server logs.
- `mode: "no-cors"` hides the error but gives you an unreadable response. It is never the fix.
- `*` cannot be combined with credentials.

## Example prompt
"My React app can't call my API, it says blocked by CORS policy."
