GuidesDIAGNOSE
Access to fetch has been blocked by CORS policy
When Chrome logs that Access to fetch has been blocked by CORS policy, the network request reached the destination, but the browser withheld the response from your script because the response headers failed validation against the page origin.
The exact console message
Access to fetch at 'https://api.example.com/data' from origin 'https://your-site.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.Chrome prints this specific wording for fetch requests, while Firefox prints its own separate phrasing for the same CORS failure.
What the browser is telling you
The message appears in two situations. For a request the browser could send directly, the response arrived, but its headers failed the origin check, so the browser withheld the body from your script. For a request that required a preflight, the OPTIONS exchange failed and the real request was never sent at all.
The text after CORS policy: is the trailing clause, and it names the exact failure condition. Reading the clause before changing any configuration saves guesswork.
Decode the trailing clause
Chrome uses a fixed prefix and attaches one of several trailing clauses depending on the exact header state. Calls made through XMLHttpRequest print the identical trailing clauses with an Access to XMLHttpRequest prefix.
| Console clause | Cause | Fix layer |
|---|---|---|
| Header missing | Chrome prints: No 'Access-Control-Allow-Origin' header is present on the requested resource. The response arrived without the header. The server omitted it or an intermediary stripped it. | API server or reverse proxy. |
| Wrong origin value | Chrome prints: The 'Access-Control-Allow-Origin' header has a value '<value>' that is not equal to the supplied origin. The server sent a fixed or stale origin value that does not match the scheme, host, and port of the page. | API server origin configuration. |
| Wildcard with credentials | Chrome prints: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The request included credentials or credentials mode was set to include, but the server returned a wildcard. | API server CORS configuration. |
| Preflight check failed (wrapper) | Chrome prints: Response to preflight request doesn't pass access control check: <inner clause> A non-safelisted request triggered an OPTIONS preflight that returned non-2xx status, a redirect, or missing headers. | OPTIONS routing and auth middleware. |
| Duplicate header values | Chrome prints: The 'Access-Control-Allow-Origin' header contains multiple values '<values>', but only one is allowed. Two separate layers emitted the header independently, such as an application middleware and a web server. | Server or proxy header deduplication. |
Fix the layer that emits the response
The resolution must occur at the layer generating the response: the API application, a reverse proxy in front of it, or an intermediary routing service. Client fetch options cannot inject response headers into an incoming payload.
- Add the missing header
Configure the server to send
Access-Control-Allow-Originon all HTTP responses, including 4xx and 5xx error responses. - Correct the origin value
Update the server configuration to match the exact calling origin, including scheme, hostname, and port, or dynamically echo the validated
Originrequest header. - Replace the wildcard for credentialed requests
When sending cookies or authorization headers, configure the server to echo the exact requesting origin instead of
*, and addAccess-Control-Allow-Credentials: true. - Fix preflight handling
Ensure OPTIONS requests return a 2xx status code without redirects, and bypass any authentication middleware that rejects unauthenticated preflight calls.
- Deduplicate emitted headers
Remove duplicate
Access-Control-Allow-Origindirectives across your application code, web server configurations like nginx, and content delivery networks.
Setting mode: 'no-cors' in the client fetch options does not solve the problem. It suppresses the console error by placing the response into an opaque state, which renders the response body, headers, and status code completely unreadable to JavaScript.
If the destination is an external third-party API that you cannot modify, you can route GET and HEAD requests through a public CORS proxy. This applies strictly to public data, because proxy operators can inspect traffic, and credentials such as cookies and authorization headers are stripped by design. Prefix the target URL with the proxy endpoint.
// Before: the API sends no CORS headers, so the browser blocks the read.
const direct = await fetch('https://jsonplaceholder.typicode.com/todos/1');
// After: prefix the URL; cors.dev answers with the headers your origin needs.
const response = await fetch(
'https://proxy.cors.dev/https://jsonplaceholder.typicode.com/todos/1',
);
const data = await response.json();
// Public data only: no keys, no cookies, GET and HEAD to public HTTPS hosts.Verify the fix
Reproduce the exact HTTP transaction from the command line using curl. Supply the Origin header that matches your front-end application to inspect the raw response headers returned by the server.
$ curl -i https://api.example.com/data \
-H "Origin: https://your-site.com"
HTTP/2 200
content-type: application/json
# No access-control-allow-origin line in this answer: that is the bug
# Chrome reports. curl itself does not care, which is why it "works" here.You can also paste the resulting raw HTTP headers directly into the CORS header checker to validate the origin match and preflight directives.
Good questions.
Why does the request succeed in Postman but fail in the browser?
Postman is an API testing client, not a web browser. It does not enforce the browser same-origin policy, does not send standard browser security headers, and does not block JavaScript from reading responses when CORS headers are missing.
Does this error mean the destination server rejected my request?
Not necessarily. In many cases, the server processed the request and returned a valid response body. The browser received the response over the network but refused to hand the data to your JavaScript code because the required CORS response headers were absent or invalid.
Can I resolve this error by setting mode: 'no-cors' in fetch?
No. The mode: 'no-cors' option silences the CORS check by downgrading the response to an opaque type. Your code will receive a response object with a status of 0, an empty header set, and a null body, preventing your application from reading the data.
Why does the API work on localhost but fail in production?
Local development setups often run behind a development server proxy that forwards requests from the same origin. When deployed to production, the browser makes direct cross-origin requests to the remote API host, which fails if the production server lacks proper CORS headers.