DevToolBox

"TypeError: Failed to fetch" の原因と対処

最終更新日: 2026-08-21公開日: 2026-08-21執筆: DevToolBox編集部

TypeError: Failed to fetch は、HTTPレスポンスが全く得られなかったときに発生する fetch API のエラーです。核心はここで、404や500のようなHTTPエラーでは 発生しません。サーバーがレスポンスを返せている限り fetch の Promise は正常に resolve し、res.okfalse になるだけです。Failed to fetch が出るのは、 CORS・接続拒否・混在コンテンツ・広告ブロッカー・リクエストの中断・DNS解決失敗など、ネットワーク層でリクエストが成立しなかった場合に限られます。

TypeError: Failed to fetch means the fetch API never received an HTTP response at all. It is not thrown for HTTP error statuses like 404 or 500 — those still resolve normally. This guide walks through the six real causes and how to tell them apart in DevTools.

HTTP Status Codes

fetchが返したステータスコードの意味をその場で検索。404/500など正常にレスポンスが返っているケースかどうかをまず切り分けられます。

今すぐ試す →

1. HTTPエラーとの違い

よくある誤解が「404や500でFailed to fetchが出る」というものですが、これは起きません。 fetch の仕様上、ネットワークエラー(レスポンスが届かない)のときだけ Promise が rejectされます。HTTPステータスがどうであれレスポンスが届いていれば resolve するので、 エラーハンドリングは次のように分けて考える必要があります。

状況fetch の挙動検知方法
404 Not Found / 500 Internal Server ErrorPromise は resolve するres.ok / res.status を確認
レスポンスが全く届かないPromise が reject するcatchTypeError: Failed to fetch

2. 原因別の切り分け

(a) CORSブロック

コンソールに Failed to fetch同時に別行でCORSエラー(has been blocked by CORS policy 等)が出ている場合はこれが原因です。 レスポンス自体はネットワークレベルでは届いていても、ブラウザがJavaScriptからの参照を ブロックするため fetch 側からは「届かなかった」扱いになります。詳しい原因切り分けと サーバ側の設定はCORSエラーの原因と正しい直し方にまとめています。

(b) 接続拒否・サーバー未起動

DevTools の Network タブでリクエストが (failed) net::ERR_CONNECTION_REFUSEDと表示される場合、宛先のポートで何も待ち受けていません。開発中に多いのは、 フロントエンドが呼んでいるAPIのポート番号が実際に起動しているポートと違う、 バックエンドのプロセスが落ちている、といったケースです。

(c) 混在コンテンツ (Mixed Content)

https:// で配信されているページから http:// のAPIを呼ぶと、 ブラウザがリクエスト自体をブロックします。コンソールにはMixed Content: The page at 'https://...' was loaded over HTTPS, but requested an insecure resource 'http://...' という警告が別途出るため、これがあれば 混在コンテンツが原因です。対処はAPI側もHTTPS化することです。

(d) 広告ブロッカー・拡張機能

Network タブに (failed) net::ERR_BLOCKED_BY_CLIENT と出る場合、 広告ブロッカーやプライバシー系拡張機能がリクエストURLをブロックしています。 URLに ads / analytics / tracking のような 文字列が含まれていると誤検知されやすいので、シークレットウィンドウ(拡張機能無効)で 再現するかを確認すると切り分けが早いです。

(e) AbortController・ページ遷移による中断

AbortController で明示的に中断した場合や、リクエスト中にページ遷移・ タブを閉じた場合もリクエストが完了せず、環境によってはFailed to fetchThe user aborted a requestになります。中断が意図した挙動であれば、AbortError かどうかをerror.name で見分けて握りつぶすのが安全です。

try {
  const res = await fetch(url, { signal: controller.signal });
  // ...
} catch (err) {
  if (err instanceof DOMException && err.name === "AbortError") {
    return; // 意図した中断なので無視
  }
  throw err; // それ以外は本当の失敗
}

(f) DNS解決失敗

net::ERR_NAME_NOT_RESOLVED が Network タブに出る場合、 ホスト名の名前解決に失敗しています。タイプミス、開発環境の /etc/hosts未設定、社内DNSの一時的な障害などが典型的な原因です。

3. DevToolsのNetworkタブでの調べ方

原因を1つずつ試す前に、まずNetwork タブで該当リクエストの状態を見るのが近道です。

4. "Failed to fetch dynamically imported module" は別原因

文言が似ていますが、Failed to fetch dynamically imported moduleは上記の6原因とは別物です。Vite等のビルドツールが生成するハッシュ付きの JSチャンクファイルへの動的 import() が404になったときに出ます。 典型的な流れは次の通りです。

  1. ユーザーがページを開いたままにしている(古いビルドのチャンクファイル名を参照)
  2. その間に新しいバージョンがデプロイされ、静的ホスティング上の古いチャンクファイルが 削除・上書きされる
  3. ユーザーが古いタブでルーティング操作をすると、存在しないファイル名への 動的importが発生し404になる

対処法はページの再読み込みを促すことです。実装としては、この特定のエラー メッセージを検出したら window.location.reload() を呼ぶ、あるいはService Worker や古いビルド成果物を残したままデプロイする(即時削除しない)運用にする、といった対策が 一般的です。

window.addEventListener("vite:preloadError", () => {
  window.location.reload();
});

5. Node.jsでの対応する挙動

Node.js 18以降に組み込まれた fetch では、同種の失敗はTypeError: fetch failedという別の文言になり、err.cause にOSレベルの詳細な原因が入ります。接続拒否の場合、 実際に確認すると次のようになります。

await fetch("http://127.0.0.1:59999/x");
// TypeError: fetch failed
//   cause: Error: connect ECONNREFUSED 127.0.0.1:59999
//     code: 'ECONNREFUSED'

ブラウザの Failed to fetch がどの原因でも同じ汎用的な文言になるのに対し、 Node.jsは err.cause.codeECONNREFUSEDENOTFOUNDなどTCP/DNSレベルの具体的な理由が入るため切り分けがしやすくなっています。 ECONNREFUSEDとETIMEDOUTの違いはECONNREFUSED と ETIMEDOUT の違い・切り分けで詳しく解説しています。

6. English summary

TypeError: Failed to fetch is thrown only when no HTTP response comes back at all — it is never thrown for HTTP error statuses like 404 or 500, which still resolve normally. The six real causes are: (1) a CORS block (check the console for a separate CORS error), (2) connection refused / server not running (net::ERR_CONNECTION_REFUSED), (3) mixed content (calling an http://API from an https:// page), (4) an ad blocker or privacy extension (net::ERR_BLOCKED_BY_CLIENT), (5) an aborted request viaAbortController or page navigation, and (6) DNS resolution failure (net::ERR_NAME_NOT_RESOLVED). The unrelated "Failed to fetch dynamically imported module" error happens when a stale tab requests a JS chunk file that no longer exists after a redeploy — reload the page to fix it. Node.js 18+'s built-in fetch reports the same class of failure as TypeError: fetch failed with a more specificerr.cause (e.g. ECONNREFUSED).

よくある質問 / FAQ

Failed to fetch とはどういう意味?
fetch() がHTTPレスポンスを全く受け取れなかったことを示す TypeError です。ネットワーク層・CORS・中断などが原因で、404や500のようなHTTPステータスが返るエラーとは根本的に異なります。
404や500エラーのときもFailed to fetchになる?
なりません。404や500はサーバーがレスポンスを返せている状態なので、fetch()のPromiseは正常にresolveし、res.okがfalseになるだけです。Failed to fetchはレスポンス自体が届かなかった場合のみ発生します。
コンソールにCORSエラーが出ていないのにFailed to fetchになる
サーバーが起動していない・ポートが違う・広告ブロッカーが該当リクエストをブロックしている・httpsページからhttpのAPIを呼んでいる、のいずれかの可能性が高いです。DevToolsのNetworkタブでリクエストが (failed) 表記になっているか、ステータス列に何が出ているかを確認してください。
Failed to fetch dynamically imported module とは別のエラー?
はい、原因が異なります。こちらはビルド済みのJSチャンクファイル(ハッシュ付きファイル名)が404になった場合に出るエラーで、多くはデプロイ後に古いタブを開いたままにしていることが原因です。ページを再読み込みすれば解決します。
Node.jsのfetchでも同じエラーになる?
Node.js 18以降の組み込みfetchでは文言が異なり、TypeError: fetch failed になります。接続拒否の場合は err.cause に ECONNREFUSED などのより詳細な原因が入っている点がブラウザと異なります。
Why does fetch throw "TypeError: Failed to fetch" instead of returning a response?
The fetch Promise only resolves when a response — even an error response like 404 or 500 — actually comes back from the network. When nothing comes back at all (blocked by CORS, connection refused, mixed content, ad blocker, aborted request, or DNS failure), the browser has nothing to resolve with, so it rejects the Promise with a generic TypeError instead.

関連ツール / Related tools

関連ガイド / Related guides