Webエンジニア向けプログラミング解説動画をYouTubeで配信中!
▶ チャンネル登録はこちら

【ITニュース解説】"Application error: a client-side exception has occurred" Is a Stale Chunk 404

2026年09月08日に「Dev.to」が公開したITニュース「"Application error: a client-side exception has occurred" Is a Stale Chunk 404」について初心者にもわかりやすく解説しています。

作成日: 更新日:

ITニュース概要

Next.jsアプリでデプロイ後、古いブラウザタブでページ遷移すると「Application error」が発生することがある。これは、デプロイで更新されたJavaScriptファイルの参照が残り、404エラーになるためだ。サーバーログが正常でも、エラーはクライアント側で起きている。自動リロードで対処できる場合もある。

ITニュース解説

あるNext.jsアプリケーションにおいて、デプロイ後に既存のWebブラウザのタブでページ遷移を行うと、「Application error: a client-side exception has occurred」というエラーメッセージが表示される問題が発生した。これは、Next.js App RouterとCloudflare Workersで構築されたプロジェクトで確認された事象である。

このエラーの具体的な症状は次の通りだ。Webサイトをブラウザで開いたまま、ページ内リンクをクリックすると、期待されるページではなく、画面全体が真っ白になり、一行のメッセージ「Application error: a client-side exception has occurred (see the browser console for more information)」が表示される。しかし、この状態でページをリロードすると、エラーは解消し、サイトは正常に機能する。このエラーは常に発生するわけではなく、特定の条件下で間欠的に現れるため、再現性が低く、原因究明を困難にしていた。

この問題の厄介な点は二つあった。一つは、発生が断続的であること。一部のタブやナビゲーションでのみ発生し、常に再現できるわけではなかった。二つ目は、エラーメッセージが非常に抽象的であることだ。このメッセージは、Reactのプロダクション環境でのエラー境界が意図的に詳細な情報を隠しており、あらゆる捕捉されていないレンダリングエラーに対して表示されるため、具体的な原因を示唆しない。

当初、この問題の原因をサーバー側で探すという誤った方向に導かれた。Cloudflare Workersのログを確認したが、すべてのリクエストが正常に処理され、例外は一切記録されていなかった。例えば、wrangler tailの出力には例外の記載がなく、すべてのリクエストが200 OK(成功)を返していた。この状況を見ると、サーバーは正常に稼働しており、問題はクライアントサイドのコードにあると判断しがちだ。しかし、これは罠であった。なぜなら、クライアント側で発生した例外はサーバーログには記録されないためだ。このエラーはブラウザ内で、サーバーが正常なレスポンスを返送し終えた後に発生している。したがって、サーバーログがクリーンであることは、クライアント側の問題が存在しない証拠ではなく、単にクライアント側の問題について何も語っていない状態だった。

真の原因を特定するには、ブラウザの開発者ツール(DevTools)の利用が不可欠だった。DevToolsの「Network」タブを開いたまま、エラーが再現するようなページ遷移を行う。すると、/_next/static/...のようなパスへのリクエストが「404 Not Found」エラーを返しているのが見つかるはずだ。具体的には、GET /_next/static/chunks/app/[locale]/layout-4f2c9a1b8e.js 404のようなログが確認できるだろう。この現象が確認できれば、診断は完了だ。これは「デプロイメントスキュー」と呼ばれる問題であり、その根本にあるエラーは「ChunkLoadError」である。Reactのエラー境界がこのChunkLoadErrorを捕捉し、前述の一般的なエラーメッセージを表示していた。さらに、ブラウザの「Console」タブには、ページ上では隠されていた実際のメッセージ「ChunkLoadError: Loading chunk app/[locale]/layout failed.」が表示され、エラーの具体的な内容が明らかになる。

この「ChunkLoadError」が、なぜデプロイ後に発生するのかを理解するには、Next.jsのアプリケーション構造と静的アセットのホスティング方法を知る必要がある。Next.jsは、アプリケーションのコードを「チャンク」と呼ばれる小さなJavaScriptファイルに分割し、これらを必要に応じて動的にロードする仕組みを採用している。ユーザーが最初にページを開いたとき、アプリケーション全体が一度に読み込まれるのではなく、そのページに必要なHTMLドキュメントと初期チャンクだけが読み込まれる。そして、まだ訪問していないルートへの遷移が発生した際に、そのルートに必要なチャンクが新たにサーバーからフェッチされる。

重要なのは、これらのチャンクファイルのファイル名に含まれるハッシュ値だ。このハッシュ値は、チャンクの内容に基づいて生成される。例えば、layout.tsxというファイルを変更すると、それに対応するJavaScriptチャンクのファイル名も、内容の変更に伴ってハッシュ値が変わり、layout-4f2c9a1b8e.jsからlayout-91d0c73aa2.jsのように変化する。

これらの事実と静的アセットのホスティング方法を組み合わせると、問題の発生メカニズムが明らかになる。Cloudflare Workers Assetsを含む多くの静的ホスティング環境では、デプロイが行われると、現在のビルドで生成されたアセットのみが利用可能になり、以前のビルドで生成された古いハッシュ名のファイルはサーバーから削除される。これにより、古いファイル名へのリクエストは解決できなくなる。

具体的なエラー発生のシーケンスは次のようになる。まず、ユーザーのブラウザはビルドAでデプロイされたWebサイトを読み込む。次に、サイト管理者がアプリケーションをビルドBでデプロイする。このデプロイにより、サーバー上のビルドAのチャンクファイルは削除され、ビルドBの新しいチャンクファイルに置き換えられる。この時点で、ユーザーがまだ閉じずに開いているタブは、依然としてビルドAから学習した古いチャンクファイル名を知っている状態だ。そして、その開かれたタブでページ内のリンクをクリックしてナビゲーションが発生すると、ブラウザはビルドAのチャンクファイル名を指定してサーバーに新しいチャンクをリクエストする。しかし、サーバーにはもはやビルドAのチャンクファイルが存在しないため、404 Not Foundエラーが返される。これがChunkLoadErrorを引き起こし、最終的にReactのエラー境界が一般的なエラーメッセージを表示する、という流れだ。

このメカニズムは、エラーが間欠的に発生する理由を完全に説明する。このエラーは、デプロイ前にサイトを開いていて、デプロイ後にリロードせずにページ遷移を行ったタブにのみ影響するためだ。また、リロードするだけでエラーが解消する理由も明確になる。リロードによって、ブラウザは新しいビルドBのHTMLドキュメントを再取得し、それによってビルドBの正しいチャンクファイル名を参照するようになるためだ。開発中に頻繁なデプロイを行うと、この問題がより顕著に感じられる理由も、開いているすべてのタブがエラーの影響を受ける候補となるからである。

この問題に対する解決策は主に二つ考えられる。

一つ目は、エラー発生時に自動的に回復する仕組みを導入することだ。具体的には、Reactのエラー境界コンポーネントを活用し、特定の「ChunkLoadError」を認識した場合に、エラーメッセージを表示する代わりに自動的にページをリロードする処理を追加する。これはユーザーにとって最も親切な解決策と言える。しかし、この解決策には、他の原因でChunkLoadErrorが発生した場合でも自動リロードが実行され、本来のエラーを見逃す可能性があるという欠点がある。

二つ目は、古いビルドのアセットをサーバー上に保持し続けることだ。一部のプラットフォームでは、以前のデプロイで使われた静的アセットを一定期間サーバー上に残しておく機能が提供されている。この機能を利用すれば、古いチャンク名へのリクエストも解決されるため、404エラーの発生そのものを回避できる。これは、エラーに事後的に反応するのではなく、その原因を取り除く点でより良い解決策だが、利用できない環境もある。

筆者は、自身のプロジェクトの特性(トラフィックが少なく、デプロイ頻度が高いが、エラーが発生してもリロードで直るためユーザーへの影響は小さい)を考慮し、どちらの解決策も採用しないという結論に至った。このバグによる実際のインパクトよりも、その原因を特定するために誤った場所を何度も調査して費やした時間の方がコストが高かったと述べている。

この経験から得られる重要な教訓がいくつかある。

第一に、「一般的なエラーメッセージとクリーンなサーバーログ」という組み合わせは、情報がない状態ではなく、それ自体が重要な情報であるという認識を持つべきだ。これは、エラーがサーバーのログ記録範囲よりも「下流」、つまりブラウザ、CDN、ネットワーク経路で発生していることを明確に示している。このような状況では、ブラウザの開発者ツールなど、別の診断ツールに焦点を移すべきである。

第二に、ハッシュ化されたファイル名を持つアセットは、特定のビルドとの「契約」であるという理解が重要だ。キャッシュ、再試行、プリフェッチ、またはデプロイを跨いで参照され続ける可能性のあるあらゆるメカニズムは、この契約の変更に影響を受ける可能性がある。

第三に、問題を修正する前に、必ず再現できる状態にすることの重要性だ。今回の場合、この問題は「サイトを開く → デプロイを行う → その古いタブでリロードせずにリンクをクリックする」という手順で再現可能だ。再現性の確保は、確実なデバッグと修正の第一歩となる。

関連コンテンツ

関連IT用語