kit icon indicating copy to clipboard operation
kit copied to clipboard

Cannot read properties of undefined (reading 'universal')

Open MathiasWP opened this issue 1 year ago • 19 comments

Describe the bug

We got the following alert in Sentry:

image

Reproduction

Not sure what is triggering this, if you give me a direction i can try to create a repro.

Logs

No response

System Info

System:
    OS: macOS 14.5
    CPU: (8) arm64 Apple M1 Pro
    Memory: 121.86 MB / 16.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.11.0 - ~/.nvm/versions/node/v20.11.0/bin/node
    npm: 10.2.4 - ~/.nvm/versions/node/v20.11.0/bin/npm
    pnpm: 9.1.1 - /opt/homebrew/bin/pnpm
    bun: 1.0.0 - ~/.bun/bin/bun
  Browsers:
    Brave Browser: 125.1.66.118
    Chrome: 126.0.6478.61
    Edge: 126.0.2592.61
    Safari: 17.5

Severity

annoyance

Additional Information

No response

MathiasWP avatar Jun 19 '24 09:06 MathiasWP

~~Weird. There shouldn't be a type error for reading universal if it is undefined since there's an optional chain operator (unless node is undefined)~~

EDIT: will have to look into why node is undefined here

teemingc avatar Jun 19 '24 10:06 teemingc

Would probably need more details of which route the issue was reported for and the page options affecting that (prerendered, ssr, etc)

I can only imagine this was caused by some deployed version differences such as the user trying to load or preload a route client-side but the server routes were updated because of a new deployment, so it has a different manifest, then returns an undefined node.

we might have to add an undefined check for this, but it would be great if there was more information such as stack traces

teemingc avatar Jun 22 '24 05:06 teemingc

Would probably need more details of which route the issue was reported for and the page options affecting that (prerendered, ssr, etc)

I can only imagine this was caused by some deployed version differences such as the user trying to load or preload a route client-side but the server routes were updated because of a new deployment, so it has a different manifest, then returns an undefined node.

we might have to add an undefined check for this, but it would be great if there was more information such as stack traces

The only page option we have defined is export const ssr = true. I cannot find a lot more information on the issue, the only stack-trace i can find is already in the picture i provided. Here's a screenshot of the Trace view of the issue, i hope this can help some more. It seems like the error was triggered 12.45 minutes after the app started loading:

Screenshot 2024-06-23 at 20 17 31

Please let me know if there's anything more i can give you. We are using the session-store to force a reload of the page if a new version has been deployed + the vite:preloadError event from Vite. We do this because we have seen the "failed to load dynamically imported module" error thousands of time in our app.

Note: We added the vite:preloadError last week, which is the same time we started seeing this bug. Not sure if it's relevant, but wanted to let you know.

MathiasWP avatar Jun 23 '24 18:06 MathiasWP

The only page option we have defined is export const ssr = true.

SSR is true by default for SvelteKit, so it's likely there is a layout introducing additional page options here. I guess the most important page option would be prerender because if that's set to true you can check the html file to see if the hydration values were set correctly.

We are using the session-store to force a reload of the page if a new version has been deployed + the vite:preloadError event from Vite. We do this because we have seen the "failed to load dynamically imported module" error thousands of time in our app.

Note: We added the vite:preloadError last week, which is the same time we started seeing this bug. Not sure if it's relevant, but wanted to let you know.

I wonder if it's linked to https://github.com/sveltejs/kit/issues/9089#issuecomment-1437042343 . The expected behaviour is that if a module fails to load, SvelteKit will do a version check and refresh the page. I'm more curious why that's not happening when your "failed to load dynamically imported module" errors occur. Do you have more information to share regarding that?

teemingc avatar Jun 24 '24 15:06 teemingc

The only page option we have defined is export const ssr = true.

SSR is true by default for SvelteKit, so it's likely there is a layout introducing additional page options here. I guess the most important page option would be prerender because if that's set to true you can check the html file to see if the hydration values were set correctly.

We are using the session-store to force a reload of the page if a new version has been deployed + the vite:preloadError event from Vite. We do this because we have seen the "failed to load dynamically imported module" error thousands of time in our app. Note: We added the vite:preloadError last week, which is the same time we started seeing this bug. Not sure if it's relevant, but wanted to let you know.

I wonder if it's linked to #9089 (comment) . The expected behaviour is that if a module fails to load, SvelteKit will do a version check and refresh the page. I'm more curious why that's not happening when your "failed to load dynamically imported module" errors occur. Do you have more information to share regarding that?

I checked all the routes, and the only page option we have defined is ssr. Our app is a highly interactive enterprise app that uses web-sockets, so the initial render is only our loading screen. Not sure how much that helps...

We recently migrated our Sentry from the US to EU, so i don't have any of the issues with the "failed to load dynamically imported module" errors, but since we started using vite:preloadError we've finally been able to remove the issue (it of course helps that you can do e.preventDefault() to not get the error thrown and captured, but we also know when to refresh the page). Is there a reason SvelteKit does not use vite:preloadError?

Not sure if relevant, but we usually push code to production 3-10 times a day on the Frontend, and we have the poll-interval set to 30 seconds. We also enabled Skew Protection in Vercel, but that didn't really help.

MathiasWP avatar Jun 25 '24 07:06 MathiasWP

Got another error with Cannot read properties of undefined (reading 'universal') in Sentry, but this one had some more stack-traces:

image

MathiasWP avatar Jun 25 '24 08:06 MathiasWP

I managed to get access to our old Sentry with the Failed to fetch dynamically imported module error, but there's not a lot information in our Sentry dashboard on this issue... :/

Here's a screenshot of a full trace:

image

I remember seeing this issue once the moment a user entered the page, i was sitting right next to the user and they got the error message during our loading screen (which is within the first seconds the user visits the page).

MathiasWP avatar Jun 25 '24 08:06 MathiasWP

Any status on this issue? We're getting this error at least once a day

MathiasWP avatar Jun 28 '24 11:06 MathiasWP

Any status on this issue? We're getting this error at least once a day

I was planning to try and reproduce this locally if I found some spare time. It sounds like a type of cache / deployment skew issue similar to https://github.com/sveltejs/kit/issues/9089 . Definitely going to run through the code in https://github.com/sveltejs/kit/blob/main/packages/kit/src/runtime/client/client.js to see where we could handle the failed module loads better (maybe even add a handler for vite:preload if we haven't already).

Meanwhile, I'd recommend finding a temporary workaround from the others who posted similar experiences in #9089 . Sorry I can't get to this right away 🙏🏼 I try to take coding lightly on the weekends so I don't get burnt out from the coding at work too.

teemingc avatar Jun 28 '24 14:06 teemingc

Are you able to share how you have implemented the vite:preloadError event listener? I'd like to try and understand what caused the Cannot read properties of undefined (reading 'universal') error.

teemingc avatar Jun 30 '24 17:06 teemingc

Are you able to share how you have implemented the vite:preloadError event listener? I'd like to try and understand what caused the Cannot read properties of undefined (reading 'universal') error.

Inside our app.html file we have added the vite:preloadError event listener like this:

<script nonce="%sveltekit.nonce%">
    /**
    * @see https://vitejs.dev/guide/build.html#load-error-handling
    */
    window.addEventListener('vite:preloadError', (e) => {
	    e.preventDefault()
	    window.location.reload()
    });
</script>

AndersRobstad avatar Jul 01 '24 10:07 AndersRobstad

I've found out the Cannot read properties of undefined (reading 'universal') error is caused by preventing the original error from being thrown by calling preventDefault() on the vite:preloadError event. Ordinarily, the app loads a 500 error page when it fails to load a module, exiting the navigation code early. By preventing the error from being thrown, the navigation code tries to use the module which failed to load, which masks the real issue of the module not loading (user could be offline, file may no longer be served, etc.).

I was able to reproduce this locally by building a static website, loading a page, deleting a module, and navigating to the page that tries to load the deleted module.

I'm inclined to close this issue in favour of https://github.com/sveltejs/kit/issues/9089 . As noted by https://github.com/sveltejs/kit/issues/9089#issuecomment-1435522645 the errors are a false positive since, yes the error is thrown, but SvelteKit performs a fetch() to check the version.json file and detect if there is a new deployment, then refreshes the page. Maybe these errors should be caught and handled by SvelteKit instead of going through the handleError hook?

Currently, these two scenarios are handled the same (but maybe they shouldn't be):

  1. both the module and the version.json fails to be fetched. This could mean that the user is offline.
  2. the module fails to be fetched but the version.json was successfully fetched and has not changed. This could mean that the version.json file has been cached or the asset really is missing.

teemingc avatar Jul 01 '24 17:07 teemingc

What is your suggested solution to solve this @eltigerchino? If we remove this we will encounter the error mentioned in #9089 again, which is a real issue for us (we have seen users trying to load the app and get this error on load, which makes the whole application hang).

But if i get it right, doing the e.preventDefault on this error will not solve the issue, but just silence it?

MathiasWP avatar Jul 07 '24 20:07 MathiasWP

But if i get it right, doing the e.preventDefault on this error will not solve the issue, but just silence it?

Yes, that's right. The real issue seems to be how the assets are being served. I'd recommend reviewing how the files under _app/ are served and which cache-control headers are returned from network requests.

Which adapter are you using for your app? It could also be an issue with the specific adapter since they have different strategies for serving static files. For example, if your app is using @sveltejs/adapter-node, the static files are being served with the sirv library and we might need to fix the handler code if it is the issue.

If we remove this we will encounter the error mentioned in https://github.com/sveltejs/kit/issues/9089 again, which is a real issue for us (we have seen users trying to load the app and get this error on load, which makes the whole application hang).

I'd also recommend sending a direct request for the assets that received a 404 status when SvelteKit tries to retrieve them to see if it's an issue with SvelteKit's client-side code or if the asset really is unavailable.

If a user's app experiences this issue and renders the error page while connected to the internet, it's probably not a false positive error or that the user is trying to access the resources while offline. The issue is mostly related to how the _app/immutable/ assets and version.json file are being served.

teemingc avatar Jul 08 '24 04:07 teemingc

But if i get it right, doing the e.preventDefault on this error will not solve the issue, but just silence it?

Yes, that's right. The real issue seems to be how the assets are being served. I'd recommend reviewing how the files under _app/ are served and which cache-control headers are returned from network requests.

Which adapter are you using for your app? It could also be an issue with the specific adapter since they have different strategies for serving static files. For example, if your app is using @sveltejs/adapter-node, the static files are being served with the sirv library and we might need to fix the handler code if it is the issue.

If we remove this we will encounter the error mentioned in #9089 again, which is a real issue for us (we have seen users trying to load the app and get this error on load, which makes the whole application hang).

I'd also recommend sending a direct request for the assets that received a 404 status when SvelteKit tries to retrieve them to see if it's an issue with SvelteKit's client-side code or if the asset really is unavailable.

If a user's app experiences this issue and renders the error page while connected to the internet, it's probably not a false positive error or that the user is trying to access the resources while offline. The issue is mostly related to how the _app/immutable/ assets and version.json file are being served.

We are using the node-adapter, and we have skew-protection enabled in our Vercel settings. The users that experience this issue will not see the error page, instead the code will just not run (or at least that is what seemed to happen when this occurred during the loading screen).

When you say "I'd also recommend sending direct request for the assets that received a 404 status when SvelteKit tries to retrieve them to see if it's an issue with SvelteKit's client-side code or if the asset really is unavailable"?, do you mean that i should try to open the resource in a separate tab and see if it exists? I've done this a couple of times, and most of the times the resource is actually found if i recall correctly. But i don't want to send you on a search for the bug by something i may recall correctly. Is there a way to reproduce this so i can check it?

MathiasWP avatar Jul 08 '24 12:07 MathiasWP

We are using the node-adapter, and we have skew-protection enabled in our Vercel settings. The users that experience this issue will not see the error page, instead the code will just not run (or at least that is what seemed to happen when this occurred during the loading screen).

Curious, why use the node adapter when the vercel adapter is available?

When you say "I'd also recommend sending direct request for the assets that received a 404 status when SvelteKit tries to retrieve them to see if it's an issue with SvelteKit's client-side code or if the asset really is unavailable"?, do you mean that i should try to open the resource in a separate tab and see if it exists?

Yes, sorry. That's what I meant.

I've done this a couple of times, and most of the times the resource is actually found if i recall correctly. But i don't want to send you on a search for the bug by something i may recall correctly. Is there a way to reproduce this so i can check it?

Yes, you can load a webpage for your existing deployment then deploy a new version of your website. After the deployment has taken effect, clicking on any link of the previously opened webpage will trigger a client-side navigation, so we can observe if the Vite module preloading fails and triggers a refresh of the page. But I think Vercel skew protection is suppose to prevent this? (if it is working as intended).

teemingc avatar Jul 08 '24 14:07 teemingc

We are using the node-adapter, and we have skew-protection enabled in our Vercel settings. The users that experience this issue will not see the error page, instead the code will just not run (or at least that is what seemed to happen when this occurred during the loading screen).

Curious, why use the node adapter when the vercel adapter is available?

Sorry, i meant the Vercel adapter*

When you say "I'd also recommend sending direct request for the assets that received a 404 status when SvelteKit tries to retrieve them to see if it's an issue with SvelteKit's client-side code or if the asset really is unavailable"?, do you mean that i should try to open the resource in a separate tab and see if it exists?

Yes, sorry. That's what I meant.

I've done this a couple of times, and most of the times the resource is actually found if i recall correctly. But i don't want to send you on a search for the bug by something i may recall correctly. Is there a way to reproduce this so i can check it?

Yes, you can load a webpage for your existing deployment then deploy a new version of your website. After the deployment has taken effect, clicking on any link of the previously opened webpage will trigger a client-side navigation, so we can observe if the Vite module preloading fails and triggers a refresh of the page. But I think Vercel skew protection is suppose to prevent this? (if it is working as intended).

That's what i also thought, i would imagine the skew protection to solve this problem 🤔

MathiasWP avatar Jul 08 '24 19:07 MathiasWP

You can also try to reproduce it then check the Vercel logs to view in detail which assets are returning a 404 status.

teemingc avatar Jul 09 '24 15:07 teemingc

We've had progress on reproducing the Failed to fetch dynamically imported module issue consistently. Read https://github.com/sveltejs/kit/issues/12592 for more info 👍

MathiasWP avatar Aug 19 '24 10:08 MathiasWP

closing this in favour of https://github.com/sveltejs/kit/issues/12592

teemingc avatar Oct 28 '24 06:10 teemingc