Dashboard

What Is a CORS Error and How to Fix It in an AI-Built App

A CORS error means your browser blocked a cross-origin request. Why it happens, why the wildcard fix is risky, and a safe allow-list you can paste in.

Steve Jefferson
Steve Jefferson
Developer Advocate
2 October 20261 min read

A CORS error means your browser refused to let a web page read a response from a different origin, because the server did not say that origin is allowed. The server is usually working fine. The fix is to have your API send the right Access-Control headers for the exact site that calls it, not to switch the check off.

AI builders hit this constantly: the front end runs on one address, the API on another, and the first request fails with a red console message. Here is what the message means and how to answer it safely.

What CORS actually is

MDN defines Cross-Origin Resource Sharing as "an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources." The reason it exists is the same-origin policy: by default, a script can request resources only from the origin its page was loaded from, unless the response includes the right CORS headers. The MDN guide to CORS is the reference for everything below.

An origin is the combination of scheme, domain, and port. So http://localhost:5173 calling http://localhost:3000 is cross-origin, as is https://app.example.com calling https://api.example.com.

Two facts change how you think about it:

  • The browser enforces CORS, not the server. The server only sends headers. A request from curl, a script, or another server ignores CORS entirely.

  • The error hides detail from your code. MDN notes that CORS failures produce errors, but the specifics are not available to JavaScript. Read the browser console and the network tab instead.

Why a preflight request appears

For requests that could change data, browsers first send an OPTIONS request, called a preflight, asking the server what it permits. MDN says this applies to HTTP methods other than GET, or POST with certain content types. Sending a JSON body with a Content-Type: application/json header, or an Authorization header, is enough to trigger one.

A typical preflight asks:

http
OPTIONS /orders HTTP/1.1
Origin: https://app.example.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type,authorization

And your server has to answer with something like:

http
Access-Control-Allow-Origin: https://app.example.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
Access-Control-Max-Age: 86400

If your API has no handler for OPTIONS, or returns an error or redirect, the real request is never sent.

The common errors and their fixes

What the console says

Likely cause

Fix

No Access-Control-Allow-Origin header is present

The API did not send it at all

Add the header for your front-end origin

Wildcard not allowed when credentials are included

You send cookies or auth and answer with *

Return the exact origin instead of *

Preflight response was not successful

No OPTIONS handler, or it errors

Answer OPTIONS with a 2xx and the allow headers

Request header not allowed

A header you send is not in Allow-Headers

List it, for example Authorization

MDN's rule for credentialed requests is explicit: the server must not use the * wildcard for Access-Control-Allow-Origin, Allow-Headers, or Allow-Methods, and must give explicit values. It also notes that some browsers do not follow redirects after a preflight.

A safe allow-list to paste into your server

The tempting fix, and the one an AI assistant will often offer, is Access-Control-Allow-Origin: *. It silences the error, and for a fully public, read-only API it can be acceptable. For anything using cookies or sign-in it will not work, and for anything else it is the wrong habit. Prefer an allow-list:

javascript
const ALLOWED = new Set([
  'https://app.example.com',
  'http://localhost:5173',
]);

function corsHeaders(origin) {
  if (!origin || !ALLOWED.has(origin)) return {};
  return {
    'Access-Control-Allow-Origin': origin,
    'Vary': 'Origin',
    'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
    'Access-Control-Allow-Headers': 'Content-Type, Authorization',
    'Access-Control-Max-Age': '86400',
  };
}

export async function handler(req) {
  const headers = corsHeaders(req.headers.get('Origin'));

  if (req.method === 'OPTIONS') {
    return new Response(null, { status: 204, headers });
  }

  // ... your real logic here ...
  return new Response(JSON.stringify({ ok: true }), {
    headers: { 'Content-Type': 'application/json', ...headers },
  });
}

Three details matter. The origin is echoed back only when it is on your list. Vary: Origin tells caches that the response depends on who asked. And OPTIONS gets its own early return, so the preflight never reaches your business logic. Remove the localhost entry before you go live.

CORS is not security for your data

This is the point most tutorials skip. Because the browser enforces CORS, a strict policy does not stop anyone from calling your API directly. It only controls which websites' scripts can read the responses inside a visitor's browser. Your real protection is authentication and authorization on the server, and, if you use a database exposed to the browser, row level security.

The reverse also holds: a wildcard origin does not by itself expose private data to other sites, as long as your API requires credentials the other site cannot send. Treat CORS as a correctness rule, and fix real access control separately. The checks in how to review AI-generated code before you ship it and how to add rate limiting to an AI-built app cover that side.

Debugging checklist

  1. Open the browser network tab and find the failing request. Look for a preceding OPTIONS call.

  2. Compare the request's Origin header with your allow-list, character by character. A trailing slash or http versus https mismatch is enough to fail.

  3. Confirm the response, not just the preflight, includes the allow-origin header.

  4. Check that no proxy, redirect, or error page is answering before your code runs.

  5. Hand the failing request and response headers to your AI assistant along with the allow-list code, as in how to get an AI coding agent to explain a stack trace.

FAQ

What does a CORS error mean?

The browser blocked a script from reading a response from another origin, because the response lacked the headers that permit that origin.

How do I fix a CORS error?

Have the server send Access-Control-Allow-Origin for your exact front-end origin, answer OPTIONS preflight requests, and list any custom headers in Access-Control-Allow-Headers.

Is it safe to use Access-Control-Allow-Origin: *?

It can be fine for a public API that needs no credentials. It does not work with cookies or auth headers, and an explicit allow-list is the safer default.

Why does CORS work in Postman or curl but not the browser?

Because CORS is enforced by browsers. Other tools do not apply it.

How did this land?

About the author

Steve Jefferson
Steve Jefferson

Developer Advocate

Steve builds something with Swarmz every week and writes up what worked, what broke, and what he'd do differently. Tutorials and hands-on guides are his lane.

Share

Get the next post in your inbox

One email a month. Product updates, engineering posts, and the best of Built with Swarmz.

I agree to receive emails about AI building tips and Swarmz product news. Unsubscribe any time.