When debugging a cross-origin API call that fails in a web browser, developers frequently look at the intended POST or PUT request. However, the root cause is often that the preliminary OPTIONS preflight request failed before the main request was ever sent.
How the OPTIONS preflight fits into the request flow
In standard browser operation for non-simple cross-origin requests:
- Step 1 (Preflight): The browser automatically issues an
OPTIONSrequest carryingOrigin,Access-Control-Request-Method, andAccess-Control-Request-Headers. - Step 2 (Evaluation): The browser evaluates the server’s HTTP status code and
Access-Control-Allow-*response headers. - Step 3 (Actual Request): If and only if the preflight passes, the browser sends the actual
POST,PUT, orDELETErequest with the payload.
If Step 2 fails, Step 3 never occurs. The actual request is canceled by the browser client.
Missing or mismatched CORS response headers
Even if the server returns a successful status code like 200 OK or 204 No Content to the OPTIONS request, the preflight will still fail if required CORS headers are missing or mismatched:
- Missing
Access-Control-Allow-Origin: The preflight response must specify the requesting origin. - Missing or incomplete
Access-Control-Allow-Methods: If the client intends to send aPUTrequest, the header must includePUT. - Missing or incomplete
Access-Control-Allow-Headers: If the client sendsAuthorizationorContent-Type: application/json, those header names must be explicitly enumerated inAccess-Control-Allow-Headers.
OPTIONS endpoint or route behavior
A preflight failure often happens because the server backend router is not configured to respond to the OPTIONS HTTP method:
- Some web application routers and API frameworks match routes strictly by HTTP method. If a route defines only
POST /v1/items, an incomingOPTIONS /v1/itemsrequest may trigger an automatic404 Not Foundor405 Method Not Allowed. - To fix this, CORS middleware must handle
OPTIONSrequests globally across all API routes before route matching occurs.
HTTP 401, 403, 404, and 405 during preflight
Preflight requests frequently encounter standard HTTP error status codes for specific structural reasons:
401 Unauthorized and 403 Forbidden
The browser intentionally does not send credentials (such as Authorization headers or cookies) with an OPTIONS preflight request. If the backend server places an authentication middleware before its CORS middleware, the unauthenticated OPTIONS request is rejected with 401 Unauthorized or 403 Forbidden. The browser treats this as a preflight failure.
404 Not Found
The router or gateway does not have a route defined for OPTIONS on that specific path.
405 Method Not Allowed
The server recognizes the resource path but rejects the OPTIONS method.
CORS failure versus ordinary API error
It is essential to distinguish between a CORS preflight failure and an error returned by your actual API business logic:
- Preflight Failure: The
OPTIONSrequest failed or returned invalid CORS headers. The actual request was never transmitted to the server. No database changes or server-side side effects occurred. - Ordinary API Error: The preflight succeeded (or was not required), and the actual
POSTrequest was executed by the server. The server then returned400 Bad Request,401 Unauthorized, or500 Internal Server Errorwith properAccess-Control-Allow-Originheaders. In this case, your frontend JavaScript can read the error response body directly.
What to inspect in DevTools
When diagnosing a preflight error:
- Open Browser DevTools and select the Network tab.
- Filter by Fetch/XHR or All.
- Look for the request with the
OPTIONSmethod. - Check the Status Code of the
OPTIONSline:- If it is
401or403, verify middleware ordering on the server. - If it is
404or405, verify router and gateway handling forOPTIONS. - If it is
200or204, inspect the Response Headers to confirmAccess-Control-Allow-*values.
- If it is
Common causes
Authentication Middleware Intercepts OPTIONS Requests
Backend authentication filters or API gateways require auth tokens on all requests, rejecting unauthenticated OPTIONS preflights with 401 Unauthorized or 403 Forbidden.
Router or Endpoint Rejects OPTIONS with 404 or 405
The web application routing layer explicitly maps only GET or POST handlers, rejecting OPTIONS preflights with 404 Not Found or 405 Method Not Allowed.
Preflight Response Omits Required Access-Control Headers
The server responds with 200 or 204 but omits Access-Control-Allow-Methods or Access-Control-Allow-Headers covering the requested method and headers.
Reverse Proxy or Ingress Gateway Drops Preflight Requests
An intermediate edge proxy, load balancer, or web application firewall (WAF) blocks OPTIONS methods or fails to return CORS response headers.
What to check before changing code
- Inspect status and headers in DevTools: Check the Network tab for the preliminary
OPTIONSrequest. Determine whether it returned an error status code (401,403,404,405) or succeeded without required CORS headers. - Review server middleware order: Ensure that CORS middleware runs before any authentication guards or route-specific handlers.
- Verify method and header lists: Ensure the server’s
Access-Control-Allow-MethodsandAccess-Control-Allow-Headersmatch what the browser client is requesting.
How to verify the fix
Simulate the browser’s preflight request with curl:
curl -i -X OPTIONS https://api.example.test/v1/items \
-H "Origin: https://app.example.test" \
-H "Access-Control-Request-Method: POST" \
-H "Access-Control-Request-Headers: authorization, content-type"
Verify that the response returns 200 OK or 204 No Content, includes Access-Control-Allow-Origin, Access-Control-Allow-Methods, and Access-Control-Allow-Headers, and contains no auth error body.
Key takeaway
A failing preflight request prevents the browser from sending your actual API request. Look directly at the OPTIONS request in DevTools Network to determine whether the failure was caused by auth middleware interception (401/403), unhandled routing (404/405), or missing Access-Control-Allow-* response headers on the backend.