Guides / Prompting and shipping
How to Fix CORS Errors (and Why They Happen)
What CORS errors mean, why browsers block cross-origin requests, and how to fix them on the server, with preflight and credentials, or with a same-origin API.
Mythex Team · · 6 min read
A CORS error means your web page tried to read a response from a different origin (another domain, port or protocol), and that server didn't send headers saying it's allowed. Browsers block the response to protect users. You fix it on the server, by returning an Access-Control-Allow-Origin header for your site's origin and handling OPTIONS preflight requests, or you avoid it by sending the request through your own backend on the same origin.
It's one of the most confusing errors in web development because the request often reaches the server fine. This guide explains what's happening and how to fix each variant.
What "origin" means
An origin is the combination of protocol, domain and port:
| URL | Origin |
|---|---|
https://myapp.com/dashboard | https://myapp.com |
https://api.myapp.com/users | https://api.myapp.com (different subdomain, so different origin) |
http://localhost:5173 | http://localhost:5173 |
http://localhost:3000 | http://localhost:3000 (different port, so different origin) |
Browsers follow the same-origin policy: JavaScript on a page can freely read responses from its own origin, but not from others. CORS (Cross-Origin Resource Sharing) is the system that lets a server opt in: "responses from me may be read by pages from these origins."
Two consequences surprise people:
- The request often reaches the server. CORS usually blocks your code from reading the response, not the server from receiving the request. A POST may have been saved even though you saw an error.
- Only browsers enforce it. curl, Postman and server-side code ignore CORS entirely. That's why "it works in Postman" tells you nothing about CORS.
Step 1: Read the exact error
Open developer tools (right-click → Inspect), go to the Console, and read the full message. Chrome's wording tells you which problem you have:
| Message contains | What's wrong |
|---|---|
No 'Access-Control-Allow-Origin' header is present | The server didn't send the header at all, or the request failed before reaching your CORS code (for example a 404 or 500) |
The 'Access-Control-Allow-Origin' header has a value '...' that is not equal to the supplied origin | The server allows a different origin than yours |
Response to preflight request doesn't pass access control check | The OPTIONS preflight failed |
...must not be the wildcard '*' when the request's credentials mode is 'include' | You're sending cookies, and the server replied with * |
Request header field authorization is not allowed | The server didn't list that header in Access-Control-Allow-Headers |
Then open the Network tab, find the failing request (and any OPTIONS request before it), and look at its status code and response headers.
Check the status code first. Many "CORS errors" are really a server error in disguise. If the server crashes or returns a 404, its error response often lacks CORS headers, so the browser reports CORS instead of the real problem. Fix the 500 or 404, and the CORS error may disappear.
Step 2: Decide whether you should call that API from the browser at all
Before adding headers, ask: should the browser be calling this API directly?
- A third-party API that needs a secret key (OpenAI, Stripe secret key, most email services) should never be called from the browser. The key would be visible to every visitor. Call it from your backend instead, and the CORS problem disappears, because server-to-server requests aren't subject to CORS. See how to keep API keys safe.
- A third-party API you don't control that doesn't send CORS headers can't be fixed from your side. Call it from your backend.
- Your own API can be fixed by configuring it properly. Continue below.
Step 3: Fix it on your server
The server must add the right headers to its responses, including error responses.
For the actual request, send:
Access-Control-Allow-Origin: https://myapp.com(your frontend's exact origin, no trailing slash)Vary: Origin, if the value depends on which origin asked
For the preflight OPTIONS request, respond with a success status (200 or 204) and:
Access-Control-Allow-Origin: https://myapp.comAccess-Control-Allow-Methods: GET, POST, PUT, PATCH, DELETEAccess-Control-Allow-Headers: Content-Type, Authorization(every custom header you send)- Optionally
Access-Control-Max-Age: 600, so the browser caches the preflight for a while
Most frameworks have a package or setting that does this. In Express, the cors package; in FastAPI, CORSMiddleware; in ASP.NET Core, AddCors; in Spring, @CrossOrigin or a CORS configuration. A typical Express setup:
import cors from "cors";
app.use(cors({
origin: ["https://myapp.com", "http://localhost:5173"],
credentials: true,
}));
Put CORS handling before your routes and authentication, so preflight requests (which carry no login) aren't rejected with a 401.
With an AI builder, describe the setup precisely:
The frontend at
https://myapp.comcalls the API athttps://api.myapp.comand gets "Response to preflight request doesn't pass access control check". Configure CORS on the API to allow exactlyhttps://myapp.comand the preview origin, allow GET, POST, PATCH, DELETE with Content-Type and Authorization headers, handle OPTIONS before auth, and include CORS headers on error responses too.
Step 4: Handle cookies and credentials
If your frontend sends cookies (for example, a login session) to another origin, both sides must agree:
- The frontend sets
credentials: "include"onfetch, orwithCredentials: truein axios. - The server sends
Access-Control-Allow-Credentials: true. - The server's
Access-Control-Allow-Originmust be the exact origin, not*.
Cross-site cookies also need SameSite=None; Secure on the cookie, and some browsers restrict third-party cookies further. That's one more reason to prefer the approach in Step 5.
Step 5: Avoid CORS with a same-origin setup
Often the cleanest fix is to not make cross-origin requests at all. Serve the API from the same origin as the page, for example at https://myapp.com/api/...:
- In development, most dev servers can proxy. Vite's
server.proxysetting can forward/apito your backend on another port, so the browser only ever talks to one origin. - In production, route
/apito the backend through your host's rewrite or proxy settings, or serve the frontend and API from one server.
The frontend then calls a relative path like fetch("/api/orders"). There's no cross-origin request, no preflight across origins, and no cookie headaches. It also means you don't hard-code an API domain that differs between preview and production.
Change the frontend to call the backend with relative /api paths instead of a full URL, and set up a dev proxy so /api forwards to the API server. Then remove any CORS settings we no longer need.
What not to do
mode: "no-cors"infetch. It doesn't bypass anything; it gives your code an empty, unreadable response.- Browser extensions that disable CORS. They only change your browser. Every visitor still sees the error.
- Public "CORS proxy" services for real apps. They can read and change everything passing through them, and they go down.
Access-Control-Allow-Origin: *on an API that uses logins. It doesn't work with credentials anyway, and it's the wrong default for private data.- Reflecting any
Originheader back with credentials allowed. That lets any website make logged-in requests on your users' behalf. Use an allowlist.
Common causes in AI-built apps
| Situation | Fix |
|---|---|
| Frontend calls a third-party API with a secret key | Move the call to the backend |
| Works in preview, fails on the published domain | Add the published and custom-domain origins to the allowlist, or use relative /api paths |
| Error only on POST, PUT or DELETE | Preflight not handled; add OPTIONS handling and allowed headers |
| Error appeared after adding login | Credentials need an exact origin and Allow-Credentials |
| "CORS error" but the Network tab shows 500 | Fix the server error first |
API URL hard-coded to localhost | Use relative paths or a per-environment setting |
CORS in Mythex
When a Mythex project has a website and an API server, both run as services in the same project, and you can switch between them in the preview. Asking the agent to have the frontend call the backend through a relative /api path, proxied in development, avoids most CORS problems. If you do need cross-origin calls, give the agent the exact error from the console and the origins involved. Check the result on the published app too, since its address differs from the preview. See Multi-service apps and API backends in the docs, and our guides on debugging an AI-built app and frontend vs backend.
CORS checklist
- Read the full console error and the failing request's status code
- Ruled out a hidden 404 or 500
- Secret-key APIs called from the backend, not the browser
- Server sends
Access-Control-Allow-Originwith exact allowed origins -
OPTIONSpreflight answered with allowed methods and headers, before auth - CORS headers present on error responses
- Credentials: exact origin,
Allow-Credentials: true, correct cookie settings - Preview, published and custom-domain origins all covered, or relative
/apipaths used - No
no-cors, public proxies, or reflect-any-origin shortcuts
Questions
What does a CORS error mean?
Your page, loaded from one origin, tried to read a response from a different origin, and that server's response didn't include headers allowing it. The browser blocks your code from reading the response. The fix is on the server, or in how the request is routed, not in the frontend code.
Can I fix a CORS error from the frontend?
Not properly. Settings like mode: 'no-cors' only hide the response from your code. You fix it by making the server send the right Access-Control-Allow-Origin header, or by calling the API from your own backend or a same-origin proxy.
Is Access-Control-Allow-Origin: * safe?
It's fine for public data that anyone may read, like a public API with no login. It can't be used with cookies or other credentials, and for private APIs you should list the exact origins that are allowed.
Why does my request work in Postman or curl but not in the browser?
CORS is enforced by browsers only. Tools like Postman and curl don't apply it, so a request can succeed there and still be blocked when page JavaScript makes it.
What is a preflight request?
For requests that aren't simple, such as a JSON POST or one with an Authorization header, the browser first sends an OPTIONS request asking the server which methods and headers are allowed. If that OPTIONS request fails or lacks the right headers, the real request is never sent.