CORS errors: the server answered, the browser said no
The most misdiagnosed error in web development is not a server crash. It is a browser enforcing a permission slip your server never signed.
WrongThe API is down: I'm getting a CORS error.
RightThe API answered, but its response lacked an Access-Control-Allow-Origin header that permits my origin, so the browser withheld it.
What people get wrong#
You call an API from your frontend, the console turns red, and you see something like this:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://api.example.com/orders. (Reason: CORS header 'Access-Control-Allow-Origin' missing).
The instinctive reading is "the API is broken." Usually it isn't. In many cases the request reached the server, the server did its work and sent back a perfectly good response. The browser then looked at that response, found no permission to share it with your page, and refused to hand it to your JavaScript.
That is the whole point of CORS. Browsers enforce the same-origin policy: a script loaded from one origin (scheme, host and port) cannot freely read responses from another. Cross-Origin Resource Sharing is the opt-in mechanism, now defined in the Fetch Standard, by which a server says "yes, that origin may read this."
Why it happens#
Three details make CORS errors feel more mysterious than they are.
Your code can't see the reason. MDN is explicit: for security reasons, specifics about what went wrong with a CORS request are not available to JavaScript. Your fetch() just rejects with a generic network error. The real explanation is only in the browser console, which is why "it works in curl and Postman" is such a common complaint. Those tools aren't browsers and don't enforce the policy at all.
Preflights. For requests that could have side effects — custom headers, a JSON Content-Type, methods like PUT or DELETE — the browser first sends an OPTIONS preflight request asking permission. If your server or framework doesn't answer OPTIONS with the right headers (or answers it with an error status, or with a redirect that some browsers refuse to follow after a preflight), the real request never goes out. Same red message, different cause.
Credentials change the rules. If you send cookies or HTTP auth, MDN notes the server must not use the * wildcard in Access-Control-Allow-Origin; it has to echo an explicit origin, and also send Access-Control-Allow-Credentials: true. A config that works anonymously can fail the moment a user logs in.
The fix#
Frontend: fetch(url, { mode: "no-cors" }) and hope.
Server: respond with Access-Control-Allow-Origin: https://app.example.com (plus allowed methods and headers for preflights).
CORS is a permission the server grants; the client can't grant it to itself.
Most CORS errors can only be resolved on the server, because the server controls whether cross-origin access is allowed. The checklist:
- Open the browser console and the Network tab. Find the failing request and check whether there was a preflight
OPTIONSrequest before it. - Confirm the response (and the preflight response) carries
Access-Control-Allow-Originmatching your page's exact origin, scheme and port included. - For preflights, also return
Access-Control-Allow-MethodsandAccess-Control-Allow-Headerscovering what you send. - If you send credentials, use an explicit origin, not
*, plusAccess-Control-Allow-Credentials: true. - Check that error responses (401, 500) include the CORS headers too. Otherwise a real server error shows up disguised as a CORS error.
The tempting non-fixes#
mode: "no-cors" silences the error but, per MDN, gives you an opaque response: status 0, empty headers, unreadable body. That's fine for a fire-and-forget beacon and useless for reading data. Browser extensions that disable CORS only "fix" your own machine. If you don't control the API at all, the legitimate route is a small proxy on a server you do control, which fetches the resource and returns it with proper headers.
Sources
Every factual claim on this page links to one of these. Checked October 22, 2026. See how we source.
- MDN: Cross-Origin Resource Sharing (CORS) developer.mozilla.org
- MDN: CORS errors developer.mozilla.org
- MDN: Same-origin policy developer.mozilla.org
- MDN: Preflight request developer.mozilla.org
- WHATWG: Fetch Standard, CORS protocol fetch.spec.whatwg.org