CORS preflight / OPTIONS request failed

If the browser blocks a cross-origin request during preflight, the problem is usually in the OPTIONS response that is supposed to approve the real request before it is sent.

What this error means

Some cross-origin requests require a preflight before the browser sends the real request. The browser sends an OPTIONS request describing the method and headers it wants to use.

If that preflight does not succeed, or its CORS headers do not approve the requested origin, method, and headers, the browser blocks the real request.

Check these first

  1. Open DevTools → Network and find the OPTIONS request immediately before the failure.
  2. Confirm the preflight receives a successful response instead of an auth error, server error, timeout, or failed network request.
  3. Check Access-Control-Allow-Origin and make sure it permits the page origin.
  4. Check Access-Control-Allow-Methods and make sure it includes the method the browser wants to send.
  5. Check Access-Control-Allow-Headers and make sure it permits the non-safelisted request headers listed by Access-Control-Request-Headers.
  6. Make sure middleware, authentication, a reverse proxy, or a CDN is not rejecting OPTIONS before your CORS handler runs.

See a failing preflight on a real second origin

This request intentionally triggers a preflight and tells AnotherExample’s CORS lab to reject that preflight with HTTP 403. The browser should stop before sending the real PUT request.

fetch('https://cors.anotherexample.com/api/cors/lab?preflightStatus=403&allowOrigin=*&methods=PUT,OPTIONS&headers=Content-Type', {
  method: 'PUT',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ test: true })
})
  .then(r => r.json())
  .then(console.log)
  .catch(console.error);

Change preflightStatus=403 to preflightStatus=204 and run the same request again. The controlled preflight should succeed, allowing you to compare the two cases without changing the rest of the request.

Common server-side causes

Typical causes include an OPTIONS route that is not handled, authentication running before CORS middleware, a requested method missing from Access-Control-Allow-Methods, a requested header missing from Access-Control-Allow-Headers, or a proxy/CDN returning a different response than your application.

Do not try to solve a preflight failure with mode: 'no-cors'. That produces an opaque response that normal JavaScript cannot inspect, so it is not a substitute for a correct CORS response.

Still stuck?

Compare the request in the CORS Debugger →

Paste the browser error into the Error Explainer →

Explore working and broken preflight scenarios in the Playground →