Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

__error.svelte renders in the wrong layout #2383

Closed
kevinrenskers opened this issue Sep 7, 2021 · 3 comments · Fixed by #2389
Closed

__error.svelte renders in the wrong layout #2383

kevinrenskers opened this issue Sep 7, 2021 · 3 comments · Fixed by #2389

Comments

@kevinrenskers
Copy link

kevinrenskers commented Sep 7, 2021

Describe the bug

Errors can be rendered using the wrong layout. Instead of using __layout.svelte on the same level as __error.svelte, it sometimes uses a layout of a higher level.

Reproduction

I have a repo on Github with a minimal example: https://github.com/kevinrenskers/error-repro.

Start the dev server and go to http://localhost:3000/campaigns/1/characters/1:

Screen Shot 2021-09-07 at 19 44 46

Click on "Broken link" in the list on the left. Now an error page shows up, but the error is not shown next to the list, as I would expect:

Screen Shot 2021-09-07 at 19 45 07

It definitely has something to do with the __layout.svelte hierarchy, because as soon as you delete the one in [campaignId], the error shows as expected:

Screen Shot 2021-09-07 at 19 47 06

Logs

No response

System Info

System:
    OS: macOS 12.0
    CPU: (12) x64 Intel(R) Core(TM) i9-8950HK CPU @ 2.90GHz
    Memory: 8.23 GB / 32.00 GB
    Shell: 3.3.1 - /usr/local/bin/fish
  Binaries:
    Node: 16.6.2 - /usr/local/bin/node
    Yarn: 1.22.10 - /usr/local/bin/yarn
    npm: 7.20.3 - /usr/local/bin/npm
  Browsers:
    Safari: 15.0
  npmPackages:
    @sveltejs/kit: next => 1.0.0-next.164 
    svelte: ^3.34.0 => 3.42.4

Severity

blocking all usage of SvelteKit

Additional Information

No response

@rmunn
Copy link
Contributor

rmunn commented Sep 8, 2021

I have a guess as to what's causing this. If my guess is right, it's caused by an assumption in the Svelte-Kit code that you'll have roughly the same number of __layout.svelte and __error.svelte components in your tree, and when that doesn't hold true, you get this error. To verify my theory, and possibly work around the bug, could you find any __layout.svelte components in your tree structure that don't have an __error.svelte component at the same level, and add an __error.svelte component at that level?

If I'm right about the cause, this isn't going to be as simple to fix as #2372 was, so you might need to use that workaround for a while.

@rmunn
Copy link
Contributor

rmunn commented Sep 8, 2021

Notes for myself, or whoever ends up tackling this bug: my guess is that this is caused by the array structure of the a and b arrays in routes. The a array contains the list of layout components and the page component, while the b array contains a list of error components to use if an error is thrown while trying to render any component in the a array. The assumption currently baked into the code is that if you are rendering the __error.svelte component at, say, index 1 of the b array, its layout will be found at index 1 of the a array. But that won't always be true. For example, let's say you had this structure:

  • src/routes has __layout.svelte and __error.svelte
  • src/routes/foo has only __layout.svelte
  • src/routes/foo/bar has __layout.svelte and __error.svelte

While rendering src/routes/foo/bar/quux.svelte, the a array will be [ root layout, foo layout, foo/bar layout, foo/bar/quux component ]. The b array will be [ root error, foo/bar error ]. So if /foo/bar/quux.svelte throws an exception in its load() function, the error component will be at index 1 of the b array, and it will choose index 1 of the a array to render the error. But index 1 of the a array is the foo layout, not the foo/bar layout.

This could probably be solved by inserting nulls into the a and b arrays so that their structure stays more in parallel: whenever a __layout.svelte or an __error.svelte is found, a new item is added to both the a and b arrays; that item is null if there's no layout or error at that level. So in the example above, the a array would be the same while the b array would become [ root error, null, foo/bar error ]. And, of course, the code that tries to render layouts or errors would be written to skip any nulls in a or b.

However, the existence of __layout.reset.svelte complicates that simple algorithm, and I don't yet know how to handle layout resets. Does that reset the b array at the same time? Will have to think about that one.

@rmunn
Copy link
Contributor

rmunn commented Sep 8, 2021

What I described in #2383 (comment) is actually how it works already (though undefined is inserted rather than null), so this won't be as hard to fix as I thought. I've got a bugfix written, and thanks to your minimal reproduction, I've been able to verify the fix. Now I just need to turn your repro into a unit test and I'll be able to create a PR. Thanks for a very well-written bug report that let me find the problem so quickly!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants