Updated April 2026
Blocked by CORS Policy
Access to fetch at 'https://api.example.com/data' from origin 'https://app.example.com' has been blocked by CORS policy: Response to preflight request doesn't pass access control check.
What this error means
The browser sent an OPTIONS preflight to your API and the response either returned non-CORS headers, the wrong Access-Control-Allow-Origin, or a non-2xx status. The actual request was never sent.
The most common causes
1. OPTIONS handler missing entirely
Your server doesn't handle OPTIONS at all — it returns 404 or 405. Browsers require 200 or 204 with CORS headers.
# Nginx — add OPTIONS handling BEFORE your location blocks
if ($request_method = OPTIONS) { add_header Access-Control-Allow-Origin "https://app.example.com"; add_header Access-Control-Allow-Methods "GET, POST, PUT, DELETE, OPTIONS"; add_header Access-Control-Allow-Headers "Content-Type, Authorization"; return 204;
}
2. Wrong Access-Control-Allow-Origin value
The origin in the request doesn't match what the server returns. Common issue: trailing slash, www vs non-www, http vs https.
# Check what the browser sends in the request Origin: https://app.example.com # Your server must return EXACTLY this value (or *) Access-Control-Allow-Origin: https://app.example.com
3. Missing Authorization in Access-Control-Allow-Headers
When your frontend sends an Authorization header, the preflight response must explicitly list it:
Access-Control-Allow-Headers: Content-Type, Authorization
4. Framework swallowing OPTIONS before your handler
# Express — cors() middleware must come BEFORE your route handlers
const cors = require('cors');
app.use(cors({ origin: 'https://app.example.com' }));
app.options('*', cors()); // Handle preflight for all routes
Quick debug
Open DevTools → Network → find the OPTIONS request → check the response status and headers. The preflight must return 200 or 204 with matching CORS headers.
Test your live CORS preflight — CORSFixer →