sveltejs / kit

web development, streamlined
https://kit.svelte.dev
MIT License
18.6k stars 1.92k forks source link

SPA Mode: Redirect from +layout.ts doesn't work on 404 #11099

Open dimfeld opened 11 months ago

dimfeld commented 11 months ago

Describe the bug

With the following conditions:

Expected Behavior: It either redirects or the error page shows up. Actual Behavior: Neither the error page nor the redirect works. Instead nothing loads at all.

Notes

In the actual case where I encountered this, the redirect was to a login page when we detect that the user is not logged in.

This behavior happens either on initial load or from a client-side navigation, but only when SSR is disabled.

The redirect shows up in the console as an uncaught rejection, which hints at it maybe starting the layout load function but not actually awaiting it once it can't find a page? I haven't looked into it more yet though.

Workaround

Avoid throwing the redirect if route.id is empty. Might not work for unexpected errors though?

Reproduction

https://github.com/dimfeld/sveltekit-redirect-on-404

Load the app at http://localhost:5173/bad_route or click the bad route link from the login page, and see that nothing shows up at all.

Logs

No response

System Info

System:
    OS: macOS 14.1
    CPU: (16) arm64 Apple M3 Max
    Memory: 58.39 GB / 128.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.9.0 - /opt/homebrew/bin/node
    Yarn: 1.22.21 - ~/.pnpm/yarn
    npm: 10.1.0 - /opt/homebrew/bin/npm
    pnpm: 8.10.5 - ~/.pnpm/pnpm
    bun: 1.0.13 - /opt/homebrew/bin/bun
  Browsers:
    Brave Browser: 119.1.60.118
    Safari: 17.1
  npmPackages:
    @sveltejs/adapter-auto: ^1.0.0-next.90 => 1.0.3
    @sveltejs/kit: ^1.0.0-next.587 => 1.27.6
    svelte: ^3.54.0 => 3.59.2
    vite: ^4.0.0 => 4.5.0

Severity

serious, but I can work around it

Additional Information

No response

eltigerchino commented 11 months ago

The issue stems from not handling errors thrown while rendering the root error page.

If an error occurs during hydration, such as a 404 missing route, we load the root error page. https://github.com/sveltejs/kit/blob/07c76b1c2a5c5fe79214b585f1cebc1fba4bdc94/packages/kit/src/runtime/client/client.js#L1829-L1834

The root error page includes the root layout, so run those layout files at src/routes/+layout... https://github.com/sveltejs/kit/blob/07c76b1c2a5c5fe79214b585f1cebc1fba4bdc94/packages/kit/src/runtime/client/client.js#L864-L871

We run the load function, which throws an error (in our case a redirect), and that error isn't caught anywhere. https://github.com/sveltejs/kit/blob/07c76b1c2a5c5fe79214b585f1cebc1fba4bdc94/packages/kit/src/runtime/client/client.js#L542

Ideal solution

We need to catch and handle any redirects or errors thrown from the error helper. For all other errors, we need to display the static fallback error page (according to https://kit.svelte.dev/docs/errors#responses).

when the error occurs inside the root +layout.js or +layout.server.js, since the root layout would ordinarily contain the +error.svelte component. In this case, SvelteKit uses the fallback error page.

We should handle the error thrown by the load_root_error_page call

https://github.com/sveltejs/kit/blob/07c76b1c2a5c5fe79214b585f1cebc1fba4bdc94/packages/kit/src/runtime/client/client.js#L1821-L1835

vocafeuvre commented 10 months ago

I'm getting this error too. In my case, my app is an SPA, and I've implemented a check in load() which calls error(404) whenever a certain value is not retrieved. The page just shows a white screen and in the console: image

After doing a step through in Dev Tools, I can confirm that the issue plays out just as eltigerchino narrated.

My workaround is to make an error route where I goto() every time I have an error. This won't work, it just threw the page into an infinite loop. What I did was nest my whole routes directory one level down via /(first-level)/, and place an +error.svelte file at the root.

zommerberg commented 9 months ago

Seems to be related to #11494

manhhungpc commented 8 months ago

I just opened the PR for fallback to default error page when navigating