ErrorWeb/CORS

blocked by CORS policy: No Access-Control-Allow-Origin

Why the browser blocks a fetch with No Access-Control-Allow-Origin, why it's a server-side header problem, and the real fixes versus dead ends.

Last updated

ErrorWeb/CORS
Access to fetch at 'https://api.example.com/data' from origin 'https://app.example.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

What it means: The browser made the cross-origin request and received a response, but it blocked your JavaScript from reading that response because the server didn't send a header explicitly allowing your page's origin.

Likely causes

Most probable first — with how to confirm.

  • 1.The server (API) doesn't send CORS headers at all — this is a server-side configuration issue, not something fixable from the frontend; check the Network tab's response headers for `Access-Control-Allow-Origin`.
  • 2.The server sends CORS headers, but for a different origin than yours, and your page's origin (protocol + host + port) doesn't match — a scheme or port mismatch (http vs https, :3000 vs :3001) counts as a different origin.
  • 3.The request is 'preflighted' (a custom header, a method like PUT/DELETE, or a non-standard Content-Type) and the server doesn't handle the OPTIONS preflight correctly, even though the underlying GET or POST would have worked fine.
  • 4.You're calling a production API directly from a local dev server whose origin was never allowlisted, since production APIs typically only allow their real frontend's origin.

Fixes

Safest first; destructive ones are called out.

  • →Fix it on the server: add or correct the `Access-Control-Allow-Origin` header, and handle `OPTIONS` preflight requests if you're using custom headers or non-GET/POST methods — this is the only real, permanent fix, since only the server can grant cross-origin access.
  • →For local development against an API you don't control, proxy the request through your own dev server (a Next.js API route, or a Vite/webpack dev proxy) so the browser sees a same-origin request.
  • →Don't rely on CORS-disabling browser extensions or launching the browser with security disabled to 'fix' this — it only hides the problem in your own browser and does nothing for real users.
  • →If you do control the server, avoid a wildcard `Access-Control-Allow-Origin: *` on endpoints that use cookies or auth headers — browsers reject the wildcard combined with credentials, so echo back the specific origin instead.

Part by part

blocked by CORS policy
The browser refused to hand the response to your JavaScript. The request usually reached the server and was answered — the block happens afterwards, on the client.
No 'Access-Control-Allow-Origin' header
The specific failure: the response carried no header naming which origins may read it, so the browser assumes none may.
from origin
Followed by your page's origin. That exact string is what the server has to allow — scheme, host and port together.

Common mistakes

  • Adding the Access-Control-Allow-Origin header to the request

    It is a response header. Setting it on the request does nothing at all, and the attempt is so common that it is worth stating plainly — the fix belongs on the server you are calling.

  • Access-Control-Allow-Origin: *

    Works for public data and is wrong for anything authenticated: the wildcard is rejected outright when credentials are involved, and it lets any site read the response. Name the origins you actually serve.

  • Disabling web security in the browser to get on with it

    A local workaround that changes nothing about production and creates a browser profile where every site can read every other. If you use it, use a separate profile and never for ordinary browsing.

Questions

Why does it work in Postman but not the browser?

CORS is a browser policy, not a server one. Tools outside the browser do not enforce it, so a request that succeeds in curl or Postman proves the server works and says nothing about whether a page may read it.

What is the preflight request?

An OPTIONS request the browser sends first for anything beyond a simple GET or POST — a custom header or a JSON content type triggers one. If OPTIONS is not handled, the real request never happens at all.

Does a proxy fix it?

Yes, and by removing the cross-origin part rather than by permitting it. Serving the API under your own origin means no CORS applies, which is why dev servers offer a proxy setting and why it is a legitimate production pattern too.

Why must the origin match exactly?

An origin is scheme, host and port together, so https and http differ, as do a domain and its www form and any two ports. Most "the header is set and it still fails" cases are one of those three differing.

Related in Errors