GuidesDIAGNOSE
Response to preflight request doesn't pass access control check
When Chrome logs Response to preflight request doesn't pass access control check, the browser sent an OPTIONS probe before your actual request and rejected the answer. The text after the final colon isolates the exact reason the preflight failed.
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: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.Chrome prints this generic wrapper whenever an OPTIONS preflight request fails its validation checks. The text after the final colon provides the real diagnosis for why the browser rejected the response.
What the browser is telling you
Your browser determined that the planned HTTP request required a preflight check, typically because it uses non-safelisted methods or headers such as Content-Type: application/json. Before dispatching the actual request, the browser issued an automatic OPTIONS request to verify that the server permits the cross-origin call.
The server's response to that OPTIONS probe failed one of the browser's CORS rules. Because the preflight failed, the browser terminated the request sequence immediately. The actual GET, POST, or PUT request was never transmitted to the server. You can inspect the failed OPTIONS transaction directly inside your browser's Network panel.
Decode the trailing clause
Match the specific clause at the end of the console error to find the exact misconfiguration on your server.
| Console clause | Cause | Fix |
|---|---|---|
| Header missing | Chrome prints: No 'Access-Control-Allow-Origin' header is present on the requested resource. | The server answered OPTIONS without CORS headers. Add Access-Control-Allow-Origin to all preflight responses. |
| Preflight not ok status | Chrome prints: It does not have HTTP ok status. | The OPTIONS response was non-2xx (401/403/404/5xx). Exempt OPTIONS from auth middleware, handle the route, return 200 or 204. |
| Preflight hit a redirect | Chrome prints: Redirect is not allowed for a preflight request. | The URL answered 3xx (http to https, apex to www, trailing slash). Point the client at the final URL directly. |
| 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'. | A credentialed request met a wildcard. Echo the exact request Origin instead of *. |
| Wrong origin value | Chrome prints: The 'Access-Control-Allow-Origin' header has a value '<value>' that is not equal to the supplied origin. | The preflight echoed a fixed origin. Match the incoming Origin header for allowed origins. |
| Credentials header missing | Chrome prints: The value of the 'Access-Control-Allow-Credentials' header in the response is '<value>' which must be 'true' when the request's credentials mode is 'include'. | A credentialed request lacked the credentials header. Send Access-Control-Allow-Credentials: true on the preflight. |
| Method not allowed (no wrapper) | Chrome prints: Method <METHOD> is not allowed by Access-Control-Allow-Methods in preflight response. | The allow list omitted the method. Add it to Access-Control-Allow-Methods. |
| Header field not allowed (no wrapper) | Chrome prints: Request header field <name> is not allowed by Access-Control-Allow-Headers in preflight response. | The allow list omitted a custom header the client sends. Add it to Access-Control-Allow-Headers. |
The rows marked no wrapper print directly after blocked by CORS policy: instead of inside the preflight wrapper. They mean the preflight answered 2xx with CORS headers, but the allow list omitted the method or header your request needs.
Fix the preflight response
The most frequent production cause is authentication middleware running ahead of CORS handling. Because browsers never send credentials such as cookies or the Authorization header on an OPTIONS preflight, auth middleware rejects the probe with status 401 or 403. Apply these changes to correct your preflight behavior.
- Reorder server middleware
Place your CORS handling middleware before authentication and authorization middleware so
OPTIONSrequests receive preflight headers before any auth checks run. - Exempt OPTIONS from auth checks
Ensure your authentication handlers immediately skip requests that use the
OPTIONSmethod. - Return an HTTP 2xx status
Answer valid
OPTIONSrequests with status 204 No Content or status 200 OK along with your CORS allow headers. - Eliminate preflight redirects
Verify that your client points to the canonical API endpoint, avoiding HTTP to HTTPS upgrades, apex to www changes, or missing trailing slashes that trigger 3xx redirects.
- Configure origins and credentials accurately
When sending cookies or authorization headers from the browser, echo the exact requesting origin in
Access-Control-Allow-Originand supplyAccess-Control-Allow-Credentials: true. - Expand allowed methods and headers
Populate
Access-Control-Allow-MethodsandAccess-Control-Allow-Headersto cover every method and custom header sent by the client application.
import cors from 'cors';
import express from 'express';
const app = express();
// CORS runs first and answers OPTIONS with a 204 before auth sees it.
app.use(
cors({
origin: 'https://your-site.com',
credentials: true,
}),
);
// Preflights carry no cookies or Authorization header, so any auth
// middleware mounted above the CORS layer 401s every OPTIONS request.
app.use(requireAuth);
app.post('/data', (req, res) => {
res.json({ ok: true });
});Verify the fix
Emulate the browser preflight call using curl. Include an Origin header and the Access-Control-Request-Method header to confirm that the server responds with a 2xx status and the required Access-Control-Allow-* headers.
$ curl -i https://api.example.com/data \
-X OPTIONS \
-H "Origin: https://your-site.com" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: content-type"
HTTP/2 204
access-control-allow-origin: https://your-site.com
access-control-allow-methods: POST
access-control-allow-headers: content-type
# The browser needs exactly this: a 2xx status plus the allow headers.Good questions.
Why does my preflight request arrive without an Authorization header or cookies?
By browser design, preflight OPTIONS requests never transmit user credentials such as cookies or the Authorization header. Any authentication middleware that requires credentials will consistently reject preflights if placed before the CORS handler.
Does returning an HTTP 200 OK on OPTIONS satisfy the check?
No. The preflight check requires both a 2xx status code and the appropriate Access-Control-Allow-* response headers. Returning status 200 without Access-Control-Allow-Origin still triggers an error.
Why does a GET request succeed while a POST request fails with a preflight error?
A simple GET request with standard headers does not trigger a preflight request. When you send a POST request with Content-Type: application/json, the browser identifies it as a non-safelisted content type and sends an OPTIONS preflight first.
Can a CORS proxy resolve preflight failures on third-party APIs?
If you are calling a third-party public API that you cannot modify, routing anonymous GET and HEAD requests through cors.dev supplies the required headers for any public host. Credentials are never forwarded, so the proxy serves public data only; an API you control should be fixed at its own server.