From 83cf4cfac17c9d70332a303651780df994092ece Mon Sep 17 00:00:00 2001 From: ATOM00blue <219721791+ATOM00blue@users.noreply.github.com> Date: Fri, 22 May 2026 08:24:28 +0530 Subject: [PATCH] fix: use correct relative paths when rendering an error page for a missing __data.json request When a non-existent page is requested with the `__data.json` suffix, the suffix is stripped from the URL before routing. The error page that gets rendered computed its relative asset paths from that stripped URL, so the paths ended up one directory too shallow and failed to load the app's assets in the browser. Account for the data suffix when computing the relative path depth in both the error page renderer and `$app/paths`' `resolve`/`asset`, so the paths are resolved against the URL the browser is actually at. --- .changeset/few-paths-relate.md | 5 ++++ packages/kit/src/runtime/app/paths/server.js | 8 +++++- .../kit/src/runtime/server/page/render.js | 9 ++++-- .../apps/options-2/src/routes/+error.svelte | 9 ++++++ packages/kit/test/apps/options-2/test/test.js | 28 +++++++++++++++++++ 5 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 .changeset/few-paths-relate.md create mode 100644 packages/kit/test/apps/options-2/src/routes/+error.svelte diff --git a/.changeset/few-paths-relate.md b/.changeset/few-paths-relate.md new file mode 100644 index 000000000000..31ccfee4ac49 --- /dev/null +++ b/.changeset/few-paths-relate.md @@ -0,0 +1,5 @@ +--- +'@sveltejs/kit': patch +--- + +fix: use correct relative asset paths when rendering an error page for a missing `__data.json` request diff --git a/packages/kit/src/runtime/app/paths/server.js b/packages/kit/src/runtime/app/paths/server.js index 123fe494525d..38ff6895f17c 100644 --- a/packages/kit/src/runtime/app/paths/server.js +++ b/packages/kit/src/runtime/app/paths/server.js @@ -1,6 +1,7 @@ import { base, assets, relative, initial_base } from './internal/server.js'; import { resolve_route, find_route } from '../../../utils/routing.js'; import { decode_pathname } from '../../../utils/url.js'; +import { add_data_suffix } from '../../pathname.js'; import { try_get_request_store } from '@sveltejs/kit/internal/server'; import { manifest } from '__sveltekit/server'; import { get_hooks } from '__SERVER__/internal.js'; @@ -26,7 +27,12 @@ export function resolve(id, params) { const store = try_get_request_store(); if (store && !store.state.prerendering?.fallback) { - const after_base = store.event.url.pathname.slice(initial_base.length); + // the relative path depth must reflect the URL the browser is actually at, which + // for a data request includes the `__data.json` suffix that was stripped during routing + const pathname = store.event.isDataRequest + ? add_data_suffix(store.event.url.pathname) + : store.event.url.pathname; + const after_base = pathname.slice(initial_base.length); const segments = after_base.split('/').slice(2); const prefix = segments.map(() => '..').join('/') || '.'; diff --git a/packages/kit/src/runtime/server/page/render.js b/packages/kit/src/runtime/server/page/render.js index 8b3a521977eb..0e58b63dcdb7 100644 --- a/packages/kit/src/runtime/server/page/render.js +++ b/packages/kit/src/runtime/server/page/render.js @@ -12,7 +12,7 @@ import { public_env } from '../../shared-server.js'; import { SVELTE_KIT_ASSETS } from '../../../constants.js'; import { SCHEME } from '../../../utils/url.js'; import { create_server_routing_response, generate_route_object } from './server_routing.js'; -import { add_resolution_suffix } from '../../pathname.js'; +import { add_data_suffix, add_resolution_suffix } from '../../pathname.js'; import { try_get_request_store, with_request_store } from '@sveltejs/kit/internal/server'; import { text_encoder } from '../../utils.js'; import { count_non_ssi_comments, get_global_name, handle_error_and_jsonify } from '../utils.js'; @@ -114,7 +114,12 @@ export async function render_response({ // if appropriate, use relative paths for greater portability if (paths.relative) { if (!state.prerendering?.fallback) { - const segments = event.url.pathname.slice(paths.base.length).split('/').slice(2); + // the relative path depth must reflect the URL the browser is actually at, which + // for a data request includes the `__data.json` suffix that was stripped during routing + const pathname = event.isDataRequest + ? add_data_suffix(event.url.pathname) + : event.url.pathname; + const segments = pathname.slice(paths.base.length).split('/').slice(2); base = segments.map(() => '..').join('/') || '.'; diff --git a/packages/kit/test/apps/options-2/src/routes/+error.svelte b/packages/kit/test/apps/options-2/src/routes/+error.svelte new file mode 100644 index 000000000000..c8320ab59160 --- /dev/null +++ b/packages/kit/test/apps/options-2/src/routes/+error.svelte @@ -0,0 +1,9 @@ + + +

{page.status}

+ +

base: {resolve('/')}

+

assets: {asset('/')}

diff --git a/packages/kit/test/apps/options-2/test/test.js b/packages/kit/test/apps/options-2/test/test.js index 2c4541354be4..51b01c1caa30 100644 --- a/packages/kit/test/apps/options-2/test/test.js +++ b/packages/kit/test/apps/options-2/test/test.js @@ -39,6 +39,34 @@ test.describe('paths', () => { expect(await page.textContent('[data-testid="assets"]')).toBe(`assets: ${base}`); }); + test('uses correct relative paths when rendering an error page for a missing __data.json', async ({ + request + }) => { + // a non-existent page requested with the data suffix renders the error page. Its relative + // paths must be resolved against the requested URL (including the `__data.json` suffix), + // otherwise they end up one directory too shallow and fail to load the app's assets + const path = '/basepath/this/does/not/exist/__data.json'; + const response = await request.get(path); + expect(response.status()).toBe(404); + + const html = await response.text(); + + // `resolve('/')` and `asset('/')` (from `$app/paths`) + const relative_base = /base: ((?:\.\.\/)+) { await page.goto('/basepath'); expect(new URL(page.url()).pathname).toBe('/basepath/');