How to Fix a CORS Error
"Access to fetch ... has been blocked by CORS policy" is the most-Googled frontend error - and it's fixed on the API, not the frontend. The server has to send Access-Control-Allow-Origin. Here's how.
What CORS actually is
Browsers block a page from reading responses from a different origin (scheme + host +
port) unless that server explicitly opts in with CORS headers. So a React app on
localhost:3000 calling an API on localhost:8000 is cross-origin - the browser blocks
the read unless the API says it's allowed. The fix lives on the server, not in
your fetch call.
The error decoded
Access to fetch at 'http://localhost:8000/api/stats' from origin
'http://localhost:3000' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
Translation: the API didn't send Access-Control-Allow-Origin, so the browser refused to
hand the response to your JS. (The request often reached the server fine - this is a
browser-side block on reading the reply.)
The fix: send the headers from the API
@app.after_request
def add_cors(resp):
resp.headers["Access-Control-Allow-Origin"] = "http://localhost:3000" # or a known list
resp.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS"
resp.headers["Access-Control-Allow-Headers"] = "Content-Type, Authorization"
return resp
Handle the preflight (OPTIONS)
For anything beyond a simple GET (custom headers, PUT/DELETE, JSON with auth), the browser
first sends an OPTIONS preflight asking permission. The server must answer it 200
with the same CORS headers:
@app.route("/api/<path:p>", methods=["OPTIONS"])
def preflight(p):
return ("", 204) # after_request adds the headers
Most frameworks have a one-liner (flask-cors, cors middleware in Express) that does
both - use it in real apps; the manual version above shows what it's doing.
The gotchas
*and credentials don't mix - if you send cookies/Authorization, you must set a specific origin (not*) andAccess-Control-Allow-Credentials: true.- It's not your fetch code - no header change on the client fixes CORS; the server decides.
- Preflight failures look like the main request failing - check the OPTIONS response, not just the GET/POST.
Want to try it hands-on? HeyDevJob gives you this exact setup in a live cloud workspace in your browser - edit it, run it, and see it work. Free, nothing to install.
Try it in a workspace →What you'll practice
- Sending Access-Control-Allow-Origin/Methods/Headers from the API
- Answering the OPTIONS preflight
- Handling credentials (specific origin, not *)
FAQ
How do I fix a CORS error?
On the server, not the client. The API must send Access-Control-Allow-Origin (the calling origin or a known list) plus allowed methods/headers, and answer the OPTIONS preflight with 200/204 and those same headers.
Why does the browser say 'No Access-Control-Allow-Origin'?
The cross-origin API didn't include that header, so the browser blocks your JavaScript from reading the response. Add the CORS headers to the API's responses to opt in.
What is a CORS preflight?
For non-simple requests (custom headers, PUT/DELETE, auth), the browser first sends an OPTIONS request asking if the call is allowed. The server must respond with the CORS headers, or the real request is blocked.
How do I resolve a CORS error?
Fix it on the server, not the browser: send the Access-Control-Allow-Origin header and handle the OPTIONS preflight from the API the browser is calling. The browser only enforces what the server declares.
What causes a CORS error?
A CORS error happens when a browser makes a cross-origin request and the server does not return an Access-Control-Allow-Origin header permitting the calling origin. It is a browser security policy, not a network failure.
Keep learning
Learn it by doing. Open this in a live cloud workspace, make the change yourself, and keep a record of the work you can share.
Open the workspace →