The full console message — “Access to fetch at '…' from origin '…' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present” — means a web page's JavaScript asked an API for data, and the API's server didn't include the permission slip browsers require. The request usually reached the server fine. The browser is refusing to hand over the response.
Browsers enforce the same-origin policy: a page from one origin (scheme + host + port) can't freely read responses from another. CORS is the controlled exception: the server adds headers like Access-Control-Allow-Origin declaring which origins may read its responses. No header, no read — by design, to stop malicious sites from quietly calling your bank's API with your login. Two consequences follow: the fix lives on the API server, and tools like curl/Postman don't show the error because they aren't browsers and don't enforce the policy.
Access-Control-Allow-Origin: *. For an API used by one app, name that origin exactly: Access-Control-Allow-Origin: https://app.example.com — required (not *) when requests carry credentials/cookies.Access-Control-Allow-Methods and Access-Control-Allow-Headers covering what the app sends (commonly Authorization and Content-Type). “Simple GET works, POST fails” almost always means preflight isn't handled.cors package), Django (django-cors-headers), Laravel (built-in HandleCors), Spring (@CrossOrigin / WebMvcConfigurer), ASP.NET (AddCors). Hand-set headers get overwritten or duplicated by frameworks and proxies in ways that produce stale errors.Access-Control-Allow-Origin values on one response is invalid and browsers reject it — a CDN or reverse proxy adding the header on top of the app's is a frequent cause.http://localhost:3000, http://127.0.0.1:3000, and https://localhost:3000 are three different origins.Open the browser's Network tab, click the failed request, and read both the request's Origin header and the response's Access-Control headers verbatim — then compare against what the app intended. Nine out of ten stubborn CORS bugs are a mismatch visible in that one panel: a trailing slash, the wrong scheme, a missing allowed header, or a proxy rewriting the response.
Why does it work in Postman but not the browser? Postman isn't a browser and doesn't enforce the same-origin policy. The API is fine; the browser is asking for the permission headers the API didn't send.
Is a CORS error a security problem? It's a security feature working as intended. It becomes a problem only when it's misconfigured — either blocking legitimate apps, or (rarely) an API allowing * together with credentials, which browsers reject for safety.