Failed to load module script error: intermittently serving our "base" index.html SPA file instead of JS module

We have a single page app type setup and have an index.html redirect rule in our netlify.toml file.

[[redirects]]
  from = "/*"
  to = "/index.html"
  status = 200

Intermittently we’re seeing this error:

We have a pretty robust clientside error reporting system in the base HTML file we serve, so we also know for certain that this happens at least a few times daily for our customers.

One time I was fortunate to have it happen while I had devtools open so I could see the content of the file it tried to load, and I was suprised to see, it was in fact loading our “base” index.html file as per the redirects in our netlify.toml, instead of the JS file that should have been returned.

This makes me think that something about the redirect isn’t working correctly under certain circumstances. It shoudl only be returning the index.html on HTML requests, not on sub-resource (like JS/CSS files) that are loaded by the browsers because they are referneced in the index.html.

I have yet to be able to find a way to consistently reproduce the issue. But we know for sure it’s happening multiple times a day to our customers based on the data we report back to our server via sendBeacon() API. And, like I said we’ve been able to experience the error ourselves on a couple of occasions.

Site name: manager-xchart and same thing happens on our other sites that are built the same way, for example:
case-xchart

For what it’s worth, it when I have seen it myself it seems to be more frequently happening when navigating “back” to the site in question when using the browser’s back button.

@HenrikJoreteg I don’t work for Netlify and am not ruling out there potentially being something wrong with the rewrite, but this is the behavior that I would expect if the file didn’t exist.

The hash portion of the filename c49c81e3 leads me to suspect that the file location changes when the source changes and a new build/deployment occurs.
Do you have any kind of caching in effect?

If a cached version of the page were to request the resource where it no longer exists, then the rewrite would return the contents of the /index.html.

That was my initial suspicion too. But we’ve seen this error persist when version numbers / hashes are the same.

@HenrikJoreteg It’s a very rudimentary check, but if you do see it occur again you could immediately try to access the file directly to confirm if the response is the same (still a 404 - and thus serving the /index.html) or if repeating the request serves the file.

Knowing what hash it failed on would allow you to confirm if the file in the currently live deployment contains that one too.

Again, none of this rules out there being some kind of actual issue, just things you can check while waiting for Netlify.

This is a screenshot from our error logging:

“3.7.1” is the latest version so none of the files referenced by that html should ever be missing.

@HenrikJoreteg Where does the 3.7.1 reported in the client-side generated error log originate from?
How does the 3.7.1 correlate to the file hashes?

The assumption is that if a particular client reports 3.7.1 that it couldn’t possibly request a stale hash due to the build that produced the 3.7.1 also having produced the hashes and the entire deployment being atomic?

I’ve gone to the URL mentioned in that latest screenshot, (although I’m fairly certain I’m on an entirely different page than in your first screenshot due to the number/size of resources loaded), and I can see the page loads three different index.${hash}.js files.

@nathanmartin while i appreciate your willingness to jump in here, for context I’ve been a professional web devloper for 15 years and written a couple of JS books.

I’m reporting what I think is a Netlify bug.

But yes, to answer you question, the version number, and the code that reports errors, is inline code in a tag in the index.html file itself. At build time the version number from the package.json file is injected into this html file.

The hashes are content based, so they will be the same even if it were built multiple times. You can view source on the page to see the version number and the error reporting code if you’re curious.

image

There should be no possible scenario where the index.html file loads but the corresponding resources it references are not available. If so, refreshing the page wouldn’t work either.

Mind you, it’s not sending a 404. So to my knowledge I’m not seeing any way it could just be trying to reference a file that doesn’t exist.

I’m concerned there’s something wrong with Netlify’s caching mechansim or redirect rules for these “single page app” type redirect rules.

@HenrikJoreteg Note that I’ve never said I don’t believe that it may be a Netlify bug, I explicitly never ruled it out, I don’t work for them and I’ve been also been a professional developer for a comparable amount of time (18 years and did 5 years of training :person_shrugging:)

Still, I’d freely admit you’re almost certainly a better developer than I am, but as I’m sure you’re aware we all make mistakes and it never hurts to double check things.

The ultimate aim being that you provide enough detail that Netlify cannot brush it aside as a likely mistake or cache issue on your side, and then spend time some time investigating on your behalf.

In regards to mentioning 404 I didn’t mean that as an actual status code sent to the browser, sorry for any confusion.

I’m sure you’re aware of all of this, but if you have a catch all rewrite in place of /* /index.html 200 without the force ! it won’t send a 404 status, but Netlify is still checking if the file exists and sending the contents of the /index.html with a 200 when it believes it does not.

If the file failed to load I wouldn’t anticipate that requesting it again would (or should) ever change that fact, but if your assertions are correct I’d also then expect to either be able to prove (or not) that the file in question is in that particular deployment.

We personally experienced various issues with Netlify redirects/rewrites/shadowing in the early days of Netlify so the system can definitely be busted.

Sorry, I was a bit of a jerk just then. I’m 100% capable of stupid mistakes… that’s basically what software dev is all about (lol).

I genuinely appreciate your attempts at helping. I’ve tried to rule out the more obvious options of what could be causing this… and I’ve started suspecting it could actually be an issue with netify. /me shrugs

Anyway, I thought it was worth posting, in part to see if anyone else has seen something similar.

I also realize a bug like this would be very difficult to Netlify to catch, because it would be very difficult to discover it was happening. It’s still serving up a 200 and, the browser is the one complaining about mimetypes, and as I’ve said, it’s pretty intermittent and hard to reproduce…

@HenrikJoreteg It’s fine, I’m an unashamed jerk most of the time, and I understand you don’t want to hear from a nobody, you want an informed response from a Netlify engineer.

However I understand the problem enough to know that even though it’s annoyingly intermittent you should be capable of proving what you suspect on your side.

I also know the steps I suggested for checking seem utterly stupid, but I’ll outline them again:

  1. When you spot a fresh occurrence in your GCP logs, try to access that file URL directly, repeatedly, perhaps different locations, incognito etc. Either the response is consistent, or it isn’t, I’d expect it to be consistent and always return the contents of your /index.html.
  2. Use the File Browser on the latest deployment to confirm if the file exists.

If the requests were made after the latest deployment, the file exists and requests for it are returning (even intermittently) the contents of the /index.html, then you’re right and you’ve got proof.

If the file doesn’t exist then you would need to investigate other avenues, like locally cached pages making requests for the stale asset paths.

It’s definitely worth posting, it’s just unfortunately not a super active community.


Edit: For what it’s worth, I’m the most active non-Netlify community member currently and I’ve not spotted anyone else raise it. Usually when people have raised similar issues it’s eventually been determined to be their cache strategy or custom service workers they’re running.


Apologies too if what I’ve suggested is something you’ve already checked, or is otherwise negated by something I haven’t considered, like some custom caching scheme or obscene middleware.

I ran some checks, but I don’t see anything wrong from our end in my investigation. I checked for all URLs ending in .js that received a content_type of text/html. I see about 124 instances in the past 7 days. But in all these cases, the system has been working as intended. Here’s some data:

For the deploy ID `65c2a22d8ac36f0007043f8f`:

| url                                          | count |
|----------------------------------------------|-------|
| https://manager.xchart.com/index.c8db8840.js | 12    |
| https://manager.xchart.com/index.7d879b04.js | 12    |
| https://manager.xchart.com/index.30145308.js | 8     |
| https://manager.xchart.com/index.a16848b3.js | 8     |
| https://manager.xchart.com/index.e8c2f1fb.js | 2     |
| https://manager.xchart.com/index.5b1cb04e.js | 2     |
| https://manager.xchart.com/index.efab3c1b.js | 1     |
| https://manager.xchart.com/index.6b2badf8.js | 1     |
| https://manager.xchart.com/index.c49c81e3.js | 1     |
| https://manager.xchart.com/index.09443e28.js | 1     |



65c209b417b85a00085327ab:

| url                                          | count |
|----------------------------------------------|-------|
| https://manager.xchart.com/index.a16848b3.js | 6     |
| https://manager.xchart.com/index.30145308.js | 6     |
| https://manager.xchart.com/index.1d86e307.js | 1     |
| https://manager.xchart.com/index.3dc9bff3.js | 1     |
| https://manager.xchart.com/index.e5dc93fa.js | 1     |
| https://manager.xchart.com/index.fbf678a2.js | 1     |
| https://manager.xchart.com/index.71ca5676.js | 1     |
| https://manager.xchart.com/index.08384477.js | 1     |
| https://manager.xchart.com/index.5fdbfe27.js | 1     |
| https://manager.xchart.com/index.81694abc.js | 1     |



65c1c88dc408710008eba053:

| url                                               | count |
|---------------------------------------------------|-------|
| https://manager.xchart.com/parent-app.6caf7e99.js | 1     |



65be5de9807a8b00074e5d28:

| url                                          | count |
|----------------------------------------------|-------|
| https://manager.xchart.com/index.08384477.js | 5     |
| https://manager.xchart.com/index.71ca5676.js | 5     |
| https://manager.xchart.com/index.5ed6ada3.js | 4     |
| https://manager.xchart.com/index.5b1cb04e.js | 4     |
| https://manager.xchart.com/index.60c2ff90.js | 3     |
| https://manager.xchart.com/index.e8c2f1fb.js | 3     |
| https://manager.xchart.com/index.2bf5fdce.js | 3     |
| https://manager.xchart.com/index.a383c653.js | 2     |
| https://manager.xchart.com/index.f89ae486.js | 2     |
| https://manager.xchart.com/index.28267140.js | 2     |

If you check the deployed files for any of these deploys, you’d find that the files for which we served HTML responses, were the ones that did not exist. I tried to check the referrer details of these URLs, but that doesn’t help as your website is an SPA, so all page-URLs are technically just the same index.html.

I’m not sure what to make out of this data because you seem pretty confident about @nathanmartin’s theory so far being incorrect, but I would also want to agree with that, specifically:

If based on this data, you have any other theory to propose, happy to investigate accordingly. But otherwise, as far as a “bug” is concerned, the systems have been working correctly.

Oh, and about the cache, most of these have been cache miss on the CDN, so these should be fresh responses.