🔧 Error Fixes

CORS Error Explained — What It Means and How to Fix It


Access to fetch at 'https://api.example.com' from origin 'http://localhost:3000'
has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present.

If you’ve seen this error, you’re not alone. It’s probably the most common frontend error in web development. Here’s what’s actually happening and how to fix it.

What CORS Actually Is

CORS (Cross-Origin Resource Sharing) is a browser security feature. It prevents your frontend JavaScript from making requests to a different domain than the one serving your page.

Same origin (allowed by default):

  • Your page: https://mysite.com
  • Your API: https://mysite.com/api/users

Cross origin (blocked by default):

  • Your page: http://localhost:3000
  • Your API: https://api.example.com

The browser blocks the response, not the request. Your API actually receives and processes the request — the browser just refuses to show you the response.

Fix 1: Add CORS Headers to Your Backend (Proper Fix)

The correct solution is to have your API send the right headers.

Express.js:

const cors = require('cors');
app.use(cors()); // allows all origins

// Or be specific:
app.use(cors({ origin: 'http://localhost:3000' }));

Python (Flask):

from flask_cors import CORS
CORS(app)  # allows all origins

Python (FastAPI):

from fastapi.middleware.cors import CORSMiddleware
app.add_middleware(CORSMiddleware, allow_origins=["*"])

Nginx:

location /api/ {
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
    add_header Access-Control-Allow-Headers "Content-Type, Authorization";
}

Fix 2: Use a Proxy in Development

If you don’t control the API, proxy the request through your dev server.

Vite (vite.config.js):

export default {
  server: {
    proxy: {
      '/api': {
        target: 'https://api.example.com',
        changeOrigin: true,
        rewrite: (path) => path.replace(/^\/api/, '')
      }
    }
  }
}

Now fetch('/api/users') goes through your dev server, which forwards it to the real API. No CORS issue because the browser only sees your origin.

Fix 3: Use Your Backend as a Proxy

In production, make your own backend call the external API:

// Your backend endpoint
app.get('/api/data', async (req, res) => {
  const response = await fetch('https://external-api.com/data');
  const data = await response.json();
  res.json(data);
});

Your frontend calls your backend (same origin), your backend calls the external API (server-to-server, no CORS).

Fix 4: Check for Preflight Issues

For non-simple requests (POST with JSON, custom headers), the browser sends an OPTIONS preflight request first. Your server must handle it:

// Express
app.options('*', cors()); // handle preflight for all routes

If your API returns 404 or 405 for OPTIONS requests, the preflight fails and you get a CORS error even though your GET/POST would work fine.

Fix 5: Browser Extension (Development Only)

Extensions like “CORS Unblock” disable CORS checking in your browser. Only use this for local development — it doesn’t fix the problem for your users.

Common Mistakes

“I added the header but it still doesn’t work”

  • Check if the preflight OPTIONS request is handled
  • Check if you’re sending credentials (cookies) — you need Access-Control-Allow-Credentials: true and can’t use * for origin

“It works in Postman but not in the browser”

  • Postman doesn’t enforce CORS — it’s a browser-only restriction
  • This confirms the API works; you just need the right headers

“It works in development but not in production”

  • Your dev proxy isn’t running in production
  • Update CORS headers to include your production domain

When CORS Is NOT the Problem

Sometimes the error message mentions CORS but the real issue is:

  • Network error — the API is down or unreachable
  • HTTPS mixed content — your HTTPS page is calling an HTTP API
  • DNS issue — the API domain doesn’t resolve