Skip to content

Commit 98f66e4

Browse files
committed
fix: preserve trailingSlash when error boundary truncates the branch
When an error occurs during loading, the client router truncates the branch to the nearest error boundary. If trailingSlash was configured at the page level (below the error boundary), the setting was lost, causing the URL to be rewritten without the trailing slash. Preserve the trailingSlash value from the full branch before truncation by propagating it to the error node in both load_route and set_nearest_error_page. Fixes #13516
1 parent d027236 commit 98f66e4

File tree

8 files changed

+58
-1
lines changed

8 files changed

+58
-1
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@sveltejs/kit': patch
3+
---
4+
5+
fix: preserve `trailingSlash` config when error boundary truncates the branch

packages/kit/src/runtime/client/client.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1193,10 +1193,24 @@ async function load_route({ id, invalidating, url, params, route, preload }) {
11931193

11941194
const error_load = await load_nearest_error_page(i, branch, errors);
11951195
if (error_load) {
1196+
// Preserve trailingSlash from the full branch before truncation,
1197+
// so it's not lost when the error boundary is above the node
1198+
// that defines it (#13516)
1199+
let slash;
1200+
for (const node of branch) {
1201+
if (node?.slash !== undefined) slash = node.slash;
1202+
}
1203+
1204+
const error_branch = branch.slice(0, error_load.idx).concat(error_load.node);
1205+
1206+
if (slash !== undefined) {
1207+
error_load.node.slash = slash;
1208+
}
1209+
11961210
return get_navigation_result_from_branch({
11971211
url,
11981212
params,
1199-
branch: branch.slice(0, error_load.idx).concat(error_load.node),
1213+
branch: error_branch,
12001214
status,
12011215
error,
12021216
route
@@ -2401,6 +2415,16 @@ export async function set_nearest_error_page(error, status = 500) {
24012415

24022416
const error_load = await load_nearest_error_page(current.branch.length, branch, route.errors);
24032417
if (error_load) {
2418+
// Preserve trailingSlash from the full branch before truncation (#13516)
2419+
let slash;
2420+
for (const node of branch) {
2421+
if (node?.slash !== undefined) slash = node.slash;
2422+
}
2423+
2424+
if (slash !== undefined) {
2425+
error_load.node.slash = slash;
2426+
}
2427+
24042428
const navigation_result = get_navigation_result_from_branch({
24052429
url,
24062430
params: current.params,
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<script>
2+
import { page } from '$app/state';
3+
</script>
4+
5+
<p id="trailing-slash-error">{page.error?.message}</p>
6+
<p id="trailing-slash-error-url">{page.url.pathname}</p>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<slot />
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<a href="/routing/trailing-slash/always/error-boundary/">error boundary test</a>
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export const trailingSlash = 'always';
2+
3+
export function load() {
4+
throw new Error('trailing slash error test');
5+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<p>This should not be rendered</p>

packages/kit/test/apps/basics/test/cross-platform/client.test.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1132,6 +1132,20 @@ test.describe('Routing', () => {
11321132
expect(new URL(page.url()).pathname).toBe('/routing/trailing-slash/never');
11331133
await expect(page.locator('p')).toHaveText('/routing/trailing-slash/never');
11341134
});
1135+
1136+
test('trailing slash is preserved when error boundary is above page config', async ({
1137+
page,
1138+
clicknav
1139+
}) => {
1140+
await page.goto('/routing/trailing-slash/always/');
1141+
await clicknav('a[href="/routing/trailing-slash/always/error-boundary/"]');
1142+
expect(new URL(page.url()).pathname).toBe(
1143+
'/routing/trailing-slash/always/error-boundary/'
1144+
);
1145+
await expect(page.locator('#trailing-slash-error')).toHaveText(
1146+
'trailing slash error test'
1147+
);
1148+
});
11351149
});
11361150

11371151
test.describe('Shadow DOM', () => {

0 commit comments

Comments
 (0)