Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Webpack code splitting: ChunkLoadError - Loading chunk X failed, but the chunk exists

I've integrated Sentry with my website a few days ago and I noticed that sometimes users receive this error in their console:

ChunkLoadError: Loading chunk <CHUNK_NAME> failed.
(error: <WEBSITE_PATH>/<CHUNK_NAME>-<CHUNK_HASH>.js)

So I investigated the issue around the web and discovered some similar cases, but related to missing chunks caused by release updates during a session or caching issues.

The main difference between these cases and mine is that the failed chunks are actually reachable from the browser, so the loading error does not depend on the after-release refresh of the chunk hashes but (I guess), from some network related issue. This assumption is reinforced by this stat: around 90% of the devices involved are mobile.

Finally, I come to the question: Should I manage the issue in some way (e. g. retrying the chunk loading if failed) or it's better to simply ignore it and let the user refresh manually?


2021.09.28 edit:

A month later, the issue is still occurring but I have not received any report from users, also I'm constantly recording user sessions with Hotjar but nothing relevant has been noticed so far.

I recently had a chat with Sentry support that helped me excluding the network related hypotesis:

Our React SDK does not have offline cache by default, when an error is captured it will be sent at that point. If the app is not able to connect to Sentry to send the event, it will be discarded and the SDK will no try to send it again.

Rodolfo from Sentry

I can confirm that the issue is quite unusual, I share with you another interesting stat: the user affected since the first occurrence are 882 out of 332.227 unique visitors (~0,26%), but I noticed that the 90% of the occurrences are from iOS (not generic mobile devices as I noticed a month ago), so if I calculate the same proportion with iOS users (794 (90% of 882) out of 128.444) we are near to a 0,62%. Still small but definitely more relevant on iOS.

like image 640
5imone Avatar asked Sep 03 '21 15:09

5imone


2 Answers

This is most likely happening because the browser is caching your app's main HTML file, like index.html which serves the webpack bundles and manifest.

First I would ensure your web server is sending the correct HTTP response headers to not cache the app's index.html file (let's assume it is called that). If you are using NGINX, you can set the appropriate headers like this:

location ~* ^.+.html$ {
  add_header Cache-Control "no-store max-age=0";
}

This file should be relatively small in size for a SPA, so it is ok to not cache this as long as you are caching all of the other assets the app needs like the JS and CSS, etc. You should be using content hashes on your JS bundles to support cache busting on those. With this in place visits to your site should always include the latest version of index.html with the latest assets including the latest webpack manifest which records the chunk names.

If you want to handle the Chunk Load Errors you could set up something like this:

import { ErrorBoundary } from '@sentry/react'

const App = (children) => {
  <ErrorBoundary
    fallback={({ error, resetError }) => {
      if (/ChunkLoadError/.test(error.name)) {
        // If this happens during a release you can show a new version alert
        return <NewVersionAlert />

        // If you are certain the chunk is on your web server or CDN
        // You can try reloading the page, but be careful of recursion
        // In case the chunk really is not available
        if (!localStorage.getItem('chunkErrorPageReloaded')) {
          localStorage.setItem('chunkErrorPageReloaded', true)
          window.location.reload()
        }
      }

      return <ExceptionRedirect resetError={resetError} />
  }}>
    {children}
  </ErrorBoundary>
}

If you do decide to reload the page I would present a message to the user beforehand.

like image 84
morganney Avatar answered Oct 19 '22 21:10

morganney


The chunk is reachable doesn't mean the user's browser can parse it. For example, if the user's browser is old. But the chunk contains new syntax.

Webpack loads the chunk by jsonp. It insert <script> tag into <head>. If the js chunk file is downloaded but cannot parsed. A ChunkLoadError will be throw.

You can reproduce it by following these steps. Write an optional chain and don't compile it. Ensure it output to a chunk.

const obj = {};
obj.sub ??= {};

Open your app by chrome 79 or safari 13.0. The full error message looks like this:

SyntaxError: Unexpected token '?'           // 13.js:2
MAX RELOADS REACHED                         // chunk-load-handler.js:24
ChunkLoadError: Loading chunk 13 failed.    // trackConsoleError.js:25
(missing: http://example.com/13.js)
like image 3
colder Avatar answered Oct 19 '22 19:10

colder