TypeError: Failed to fetch

Filed under APIs, auth & CORS

Most likely causeAbout 10 min · 6 steps

The browser never received any response — the URL is wrong, the server is down or unreachable, or a browser rule (CORS, mixed content) or a blocker stopped the request first.

Open the exact URL in a new tab
Find the red request in the Network tab
Check for a localhost or http URL in production

Fastest route

Give your AI this prompt

Copy it, replace the bracketed part with your error, and send it.

Preview the prompt
My app throws "TypeError: Failed to fetch" when it calls an API. I understand this means no response arrived at all — it is not a 404 or 500.

Here are my clues: the fetch code and the address it uses are [paste the fetch call and the URL value]. The Network tab shows [paste what the failed request shows, including any net::ERR code], and the console also says [paste any companion message, especially a CORS one]. It happens [everywhere / only on the deployed site / only in my browser].

Please: 1) tell me which family this belongs to — wrong address, mixed content, CORS, a blocked request, or a silent server — and what evidence decided it, 2) give me the smallest fix for that family, 3) do not rewrite my fetch code into a different library or restructure the app.

Constraints: if the evidence points at my environment variables or hosting settings rather than code, say so and name the setting to change.

Fix it yourself

Follow the repair

  1. Open the exact URL in a new browser tab. Take the address from the code — the real, complete one, including any path — and paste it into a new tab. Three outcomes, three directions: the tab shows data or a plain error page, so a server is there and the block is page-side; the tab cannot connect at all, so the address or the server is the problem; the tab redirects somewhere unexpected, revealing the address is not what you believed. Do this before reading another line of code.
  2. Find the failed request in the Network tab. Open DevTools (F12), pick the Network tab, reload the page, and click the red request. Look at what the status area says — (failed), a CORS annotation, net::ERR_ codes — and flip to the Console for the companion message the browser almost always leaves. A long CORS explanation sitting next to "Failed to fetch" means you actually have a CORS problem wearing this error as a coat; follow the CORS diagnosis for that.
  3. Check the URL your deployed app is really using. The production-only version of this bug is famous: everything works on your machine, where the API address is http://localhost:3000 — and after deploying, the page still fetches localhost, which on a visitor's machine means their computer, where nothing is listening. Log or inspect the exact URL the live app builds, and check the environment variables on your host for stale addresses, wrong ports, and missing https.
  4. Rule out mixed content. Browsers forbid a secure page from calling an insecure API. If your site loads over https:// and the fetch address begins http://, the request is blocked before it leaves and surfaces as this error. The fix is to serve the API over https (your host usually provides this automatically) and update the address the app uses.
  5. Rule out your own browser. Ad-blockers and privacy extensions maintain lists of API-looking domains and kill requests to them silently. Retest in an incognito window — which runs without most extensions — or a second browser. If the error vanishes, you have found the culprit, and it also explains the "works for me, fails for some users" reports: their blockers, their network, their rules.
  6. If the address is right and browsers are innocent, check the server. A crashed-on-startup function, an undeployed API, or an outage all present identically: silence. Open your host's dashboard and look at the API's status and logs for the exact time of a failed request (on Vercel, function logs; on other hosts, their equivalents). A service that never started leaves a boot error there — fix that, and the fetch starts getting answers, even if the first answer is an honest 500 you can then debug normally.
Why this happensOptional explanation

The fetch function makes a promise: give me an address and I will bring back whatever the server says — even if the server says "not found" (404) or "I broke" (500). Those are still answers, and fetch delivers them happily. TypeError: Failed to fetch is what happens when the promise itself cannot be kept: the browser went out with the request and came back empty-handed. No server at that address. A connection refused or timed out. Or the browser's own rulebook stopped the request before it completed — a page on https trying to fetch from an http address (mixed content), or a CORS refusal, which usually leaves its own more specific message in the console next to this one.

Because the message says nothing about which of those happened, it collects confusion. People debug their API code when the deployed page is fetching their own laptop's localhost address. They rewrite working code when an ad-blocker is eating the requests. The trick is to stop treating it as one error: it is a small crowd of network-level failures sharing a single, vague spokesperson, and your job is to find out where the request dies — wrong address, blocked in the browser, or no server listening.

  • Wrong address: a typo, an old domain, or localhost baked into the deployed app's settings.
  • Mixed content: an https page fetching an http API — blocked outright by the browser.
  • CORS: often the real cause, with its own detailed console message beside this generic one.
  • Blockers and networks: ad-blockers, privacy extensions, VPNs, and office networks silently eat requests.
  • Server silent: the API is down, crashed at startup, or not deployed where the page thinks it is.

Quick answers

Is "Failed to fetch" the same as a 404 or 500 error?

No — those mean the opposite. A 404 or 500 is a server answering you; fetch only throws "Failed to fetch" when no answer arrives at all: nothing listening at that address, the connection blocked, or the request stopped by a browser rule. That is why the error has no status code attached to it.

Why does the same URL work in Postman but fail in my browser?

Because tools like Postman and curl do not enforce the browser's rules. CORS and mixed-content blocking exist only in browsers, so a request that sails through Postman can be stopped cold in the browser. That split is itself the clue: the server is fine and the block is browser-side.

It only fails for some users. Where do I look?

Ask what is different about their setup: an ad-blocker or privacy extension blocking the API's domain, a work or school network filtering it, or a VPN. Get them to try an incognito window (which disables most extensions) and to read you the exact console line — it usually names the real blocker.

One fix, every Friday.

One real error, explained in plain English, with the fix — in your inbox every Friday. No spam, no jargon, unsubscribe anytime.