TypeError: Failed to fetch は、fetch が応答を受け取れなかった(またはブラウザーが応答を渡さなかった)ときのエラーです。 メッセージは原因によらず同じなので、Console の「1行上」や Network タブを見て原因を見分けます。

Console に一緒に出る表示 原因 直す場所
net::ERR_CONNECTION_REFUSED サーバーが動いていない・ポートが違う サーバー・URL
net::ERR_NAME_NOT_RESOLVED ホスト名が引けない(DNS) URL・DNS
has been blocked by CORS policy CORS(別のオリジンへのアクセスをサーバーが許可していない) API サーバーの応答ヘッダー
net::ERR_CERT_AUTHORITY_INVALID など HTTPS の証明書を信頼できない サーバーの証明書
Mixed Content: ... This request has been blocked HTTPS のページから HTTP の API を呼んだ API を HTTPS に

Uncaught (in promise) は、エラーを catch していないという印です。原因そのものではありません。

確認環境:Chromium 141(Playwright)、Node.js 22.22.2(確認日 2026年10月10日)。ページを http://app.test:18081、API を http://api.test:18082 の別オリジンにして、9つのパターンを再現しました。

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Failed to fetchの原因と直し方|fetchエラー」

再現した結果の一覧

# 状況 fetch の結果 Console・Network の表示
1 API サーバーが止まっている Failed to fetch net::ERR_CONNECTION_REFUSED
2 存在しないホスト名 Failed to fetch net::ERR_NAME_NOT_RESOLVED
3 API が CORS のヘッダーを返さない Failed to fetch No 'Access-Control-Allow-Origin' header is present
4 JSON の POST で、プリフライトに応えない Failed to fetch Response to preflight request doesn't pass access control check
5 credentials: 'include' で、* を返している Failed to fetch must not be the wildcard '*' when the request's credentials mode is 'include'
6 500 エラーの応答に CORS のヘッダーが無い Failed to fetch No 'Access-Control-Allow-Origin' header(中身は500)
7 信頼されていない証明書の HTTPS Failed to fetch net::ERR_CERT_AUTHORITY_INVALID
8 HTTPS のページから HTTP の API Failed to fetch Mixed Content: ... This request has been blocked
9 タイムアウト(AbortSignal.timeout) TimeoutError: signal timed out net::ERR_ABORTED

比較のため、エラーにならなかったものも並べます。

状況 fetch の結果
CORS のヘッダーあり(Access-Control-Allow-Origin: *) status=200 ok=true
500 エラー(CORS のヘッダーあり) status=500 ok=false(例外にならない)
同じオリジンへの fetch status=200 ok=true

fetch は、HTTP の 404 や 500 では例外になりません(MDN にも記載があります)。Failed to fetch が出たら、応答そのものが受け取れていないと考えます。応答は返ってきたが中身が JSON でない場合は、Unexpected token '<' という別のエラーになります。

見分け方:Console の「すぐ上」を読む

Access to fetch at 'http://api.test:18082/nocors' from origin 'http://app.test:18081'
  has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
Failed to load resource: net::ERR_FAILED
Uncaught (in promise) TypeError: Failed to fetch

一番下の Failed to fetch だけを見ても原因は分かりません。上の行に、ブラウザーが止めた理由が出ています。Network タブでは、該当のリクエストの Status 列に、失敗したことと理由が表示されます。

確認する場所 分かること
Console(エラーの上の行) CORS・Mixed Content など、ブラウザーが止めた理由
Network タブの Status 失敗したリクエストと、その理由
Network タブで OPTIONS のリクエスト プリフライト(下で説明)の応答
サーバーのログ リクエストがサーバーに届いたかどうか

原因1・2:サーバーに届いていない

API サーバーが止まっている、ポートが違う、ホスト名を打ち間違えている、のどれかです。

確認すること 方法
サーバーが動いているか ブラウザーで API の URL を直接開く、curl -i URL
URL のポート・ホスト名 開発時の localhost:3000 と localhost:8080 の取り違え
本番で環境変数が入っているか undefined/api/users のような URL になっていないか

原因3〜6:CORS(いちばん多い)

ページのオリジン(スキーム://ホスト:ポート)と、API のオリジンが違うと、API が「このオリジンからなら使ってよい」と応答ヘッダーで許可しない限り、ブラウザーは応答を JavaScript に渡しません。

3. 応答に Access-Control-Allow-Origin が無い

CORS のエラーでも、リクエストはサーバーに届いています。 確認環境のサーバーのログには GET /nocors 200 と記録されていました。サーバーは正常に応答しており、ブラウザーが JavaScript に渡さなかっただけです。そのため、直す場所はフロントエンドではなく、API サーバーの応答ヘッダーです。

Access-Control-Allow-Origin: http://app.test:18081     ← ページのオリジン(または *)

4. JSON の POST は、先に OPTIONS(プリフライト)が飛ぶ

Content-Type: application/json の POST や、Authorization ヘッダーを付けたリクエストでは、ブラウザーは本番のリクエストの前に、OPTIONS で「送ってよいか」を確認します(プリフライト)。確認環境では、サーバーのログに OPTIONS /cors-star 404 だけが残り、POST は送られていませんでした。

OPTIONS への応答に必要なヘッダーの例
Access-Control-Allow-Origin: http://app.test:18081
Access-Control-Allow-Methods: GET, POST
Access-Control-Allow-Headers: Content-Type, Authorization

OPTIONS に上のヘッダーを返すようにすると、POST まで通りました(status=200)。

5. Cookie を送るなら、* は使えない

credentials: 'include'(Cookie を送る)のときは、Access-Control-Allow-Origin: * ではブロックされました。オリジンを具体的に書いても、Access-Control-Allow-Credentials が無いと The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' でブロックされました。オリジンを具体的に書き、Access-Control-Allow-Credentials: true も返すと通りました(status=200)。

6. 500 エラーのときだけ CORS のヘッダーが付いていない

確認環境で、サーバーが 500 を返し、その応答に CORS のヘッダーが無いと、JavaScript からは Failed to fetch、Console には CORS のエラーが出ました。サーバーのログには 500 が記録されています。

Console : has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header ...
Server  : "GET /err500-nocors HTTP/1.1" 500

普段は動くのに、ときどき CORS のエラーになる場合は、このパターンを疑います。CORS のヘッダーを、正常な応答だけでなく、エラーの応答(例外ハンドラーが返す応答)にも付ける設定にします。原因の 500 は、サーバーのログで確かめます。

mode: 'no-cors' では直らない

fetch(url, { mode: 'no-cors' })  →  status=0 ok=false type=opaque

エラーは消えますが、応答の中身は読めません(type=opaque)。CORS を回避する方法ではありません。

開発中なら、開発サーバーのプロキシで同じオリジンにする

Vite(server.proxy)や webpack-dev-server の proxy で /api を API サーバーに転送すると、ブラウザーから見て同じオリジンになり、CORS の確認そのものが不要になります。確認環境でも、同じオリジンへの fetch は status=200 でした。本番では、同じドメインに配置するか、API サーバーで CORS を設定します。

原因7:証明書のエラー

自己署名の証明書や、信頼されていない認証局の証明書を使った HTTPS の API では、net::ERR_CERT_AUTHORITY_INVALID で失敗しました。ブラウザーで API の URL を直接開くと、警告の画面で理由が分かります。正しい証明書をサーバーに設定するのが直し方です。

原因8:混在コンテンツ(HTTPS のページから HTTP の API)

Mixed Content: The page at 'https://app.test:18443/page' was loaded over HTTPS,
  but requested an insecure resource 'http://api.test:18082/cors-star'.
  This request has been blocked; the content must be served over HTTPS.

HTTPS のページから http:// の API は呼べません。 ローカルでは動いて、本番(HTTPS)にしたら失敗する、というときに多い原因です。API も HTTPS にして、URL を https:// にします。

原因9(似たエラー):タイムアウトと中断

AbortSignal.timeout(ミリ秒) で時間切れにすると、TimeoutError: signal timed out になり、Failed to fetch とは区別できました。AbortController で中断した場合は AbortError です。

catch して、原因が分かる形で扱う

async function fetchJson(url, options = {}) {
  let res;
  try {
    res = await fetch(url, { signal: AbortSignal.timeout(10000), ...options });
  } catch (e) {
    if (e.name === 'TimeoutError') throw new Error(`時間切れ: ${url}`);
    // TypeError: Failed to fetch … 原因は Console・Network タブで確認
    throw new Error(`通信できません(サーバー停止・CORS・証明書・混在コンテンツ): ${url}`, { cause: e });
  }
  if (!res.ok) throw new Error(`HTTP ${res.status}: ${url}`);   // 404・500 は例外にならないので自分で判定
  return res.json();
}

JavaScript からは、CORS なのかサーバー停止なのかを区別できません(どれも同じ TypeError)。画面には「通信できませんでした」と出し、原因は開発者ツールとサーバーのログで調べます。

Node.js では「fetch failed」

サーバー側(Node.js・Next.js のサーバーコンポーネントなど)の fetch では、メッセージが fetch failed になり、cause に原因が入っています。CORS はブラウザーの仕組みなので、Node.js では起きません。

TypeError: fetch failed | cause: ECONNREFUSED connect ECONNREFUSED 127.0.0.1:18099
TypeError: fetch failed | cause: ENOTFOUND getaddrinfo ENOTFOUND no-such-host.invalid
try { await fetch(url); }
catch (e) { console.error(e.message, e.cause?.code); }   // cause.code を必ず出す

確認の手順(チェックリスト)

順番 確認すること 方法
1 Console のエラーの上の行 CORS・Mixed Content・net::ERR_...
2 Network タブ 失敗したリクエスト、OPTIONS の応答
3 サーバーに届いたか サーバーのログ。届いていれば CORS か 500 のヘッダー漏れ
4 URL ポート・ホスト名・https:// か
5 エラー時の応答にも CORS のヘッダーがあるか 500 を起こして確かめる
6 Node.js なら e.cause.code

よくある質問

Q. Postman や curl では動くのに、ブラウザーだけ Failed to fetch になります。 A. CORS の可能性が高いです。CORS はブラウザーだけが行う確認なので、Postman や curl では起きません。Console に blocked by CORS policy が出ていないかを見ます。

Q. フロントエンドのコードで CORS を直せますか。 A. 直せません。許可するのは API サーバーの応答ヘッダーです。mode: 'no-cors' はエラーが消えるだけで、中身は読めません。開発中なら開発サーバーのプロキシで同じオリジンにする方法があります。

Q. 自分のパソコンだけで起きます。 A. 広告ブロックなどのブラウザー拡張機能が、リクエストを止めていることがあります。シークレットウィンドウ(拡張機能が無効の状態)で試すと切り分けられます。

まとめ

  • Failed to fetch は応答を受け取れなかったという意味。原因は Console の上の行と Network タブで見る
  • CORS のエラーでも、リクエストはサーバーに届いている。直すのは API サーバーの応答ヘッダー
  • JSON の POST はプリフライト(OPTIONS)に応える必要がある。Cookie を送るなら * は使えない
  • 500 の応答に CORS のヘッダーが無いと、CORS のエラーに見える
  • HTTPS のページから HTTP の API は呼べない(混在コンテンツ)
  • 404・500 では fetch は例外にならない。res.ok を自分で判定する
  • Node.js では fetch failed。原因は cause に入っている

参考・出典

確認日はいずれも 2026年10月10日です。

  • MDN Web Docs「Window: fetch() method」:https://developer.mozilla.org/en-US/docs/Web/API/Window/fetch

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「Failed to fetchの原因と直し方|fetchエラー」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?