If you’ve ever seen “blocked by CORS policy” in your console, this post is for you. Let’s decode the 3 most common CORS errors and how to fix each one the right way.

Introduction
CORS errors are the frontend developer’s rite of passage.
You fetch data from an API, and your console explodes:
Access to fetch at 'https://api.example.com' from origin 'http://localhost:3000'
has been blocked by CORS policy.
You try headers, proxies, Chrome extensions, even prayers, but nothing works.
The problem isn’t your JavaScript it’s the browser enforcing the Same-Origin Policy.
Let’s break down the 3 most common CORS errors, what they actually mean, and how to fix them properly from both the frontend and backend sides.
Error #1: “No ‘Access-Control-Allow-Origin’ Header Present”
What It Means
Your frontend requested another origin (like an API domain), but the server didn’t explicitly say,
“Yes, this origin is allowed.”
The browser sees that as unsafe and blocks the response.
Example
fetch("https://api.example.com/users");
Browser sends:
Origin: http://localhost:3000
Server responds without:
Access-Control-Allow-Origin: http://localhost:3000
→ ❌ Browser blocks the response before your JavaScript can access it.
✅ Fix
On your backend, add this header:
Access-Control-Allow-Origin: http://localhost:3000
For development only (not production):
Access-Control-Allow-Origin: *
Express Example
import cors from "cors";
app.use(cors({ origin: "http://localhost:3000" }));
💡 Rule: Always fix CORS on the server, never the client.
Error #2: “Preflight Request Doesn’t Pass Access Control Check”
What It Means
Your request isn’t a “simple” one; maybe you used a custom header, or the PUT
/ DELETE
Method.
Before sending it, the browser performs a preflight OPTIONS request to check if it’s allowed.
If your server doesn’t respond correctly → the real request never happens.
Example
fetch("https://api.example.com/update", {
method: "PUT",
headers: { "Content-Type": "application/json", Authorization: "Bearer token" },
body: JSON.stringify({ name: "Rahmat" }),
});
The browser automatically sends:
OPTIONS /update
Origin: http://localhost:3000
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type, Authorization
If your server doesn’t reply with:
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Methods: GET,POST,PUT,DELETE
Access-Control-Allow-Headers: Content-Type,Authorization
→ ❌ The preflight fails silently.
✅ Fix
Make sure your backend handles OPTIONS requests and responds with all three headers above.
Express Example
app.options("*", cors()); // enable preflight for all routes
💡 Rule: The preflight must succeed before the real request is sent.
Error #3: “Credentialed Requests Can’t Use Wildcard (*) Origin”
What It Means
You’re sending cookies or tokens using:
fetch("https://api.example.com/session", {
credentials: "include",
});
…but your backend has:
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
That combination is invalid.
When credentials are included, browsers require a specific origin, not. *
.
✅ Fix
Specify your exact frontend origin:
Access-Control-Allow-Origin: http://localhost:3000
Access-Control-Allow-Credentials: true
And keep credentials: "include"
on the frontend.
Express Example
app.use(
cors({
origin: "http://localhost:3000",
credentials: true,
})
);
💡 Rule: *
And credentials are never allowed together.
Bonus: Why Postman Works but Browser Doesn’t
Because Postman is not a browser.
It doesn’t enforce CORS or Same-Origin Policy.
So when something works in Postman but fails in Chrome →
It’s almost always missing headers on your backend.
3 Debugging CORS Like a Pro
✅ Open Network → OPTIONS request in DevTools
→ check what headers are missing.
✅ Inspect the Origin header in your request
→ make sure your backend returns the same one in Access-Control-Allow-Origin
.
✅ Avoid “quick fixes” like mode: "no-cors"
Chrome extensions just hide the problem, not solve it.
Why These Errors Exist
CORS isn’t here to annoy you; it’s here to protect users.
Without it, any site could send hidden requests using your credentials to another service.
Once you understand the pattern browser asks for permission, the server grants it via headers, and it all starts making sense.
Conclusion
✅ CORS in 3 lines:
- The browser sends a
Origin
header. - Server responds with
Access-Control-Allow-Origin
friends. - The browser decides if it’s safe.
When it fails, it’s almost always one of these:
- Missing
Access-Control-Allow-Origin
- Preflight (OPTIONS) misconfigured
- Credentials with wildcard origin
Fix those three, and 95% of CORS errors disappear forever.
Call to Action
Have you run into a CORS error that wasn’t fixed by these?
Drop your setup (frontend + backend) in the comments 👇 I’ll help you debug it.
And if your teammate still says “CORS is a frontend problem”, send them this post before they add mode: "no-cors"
again 😅.
Leave a Reply