fix: don't use fork of unrelated route (#14947)
authorSimon H <5968653+dummdidumm@users.noreply.github.com>
Thu, 20 Nov 2025 08:44:44 +0000 (09:44 +0100)
committerGitHub <noreply@github.com>
Thu, 20 Nov 2025 08:44:44 +0000 (09:44 +0100)
We haven't been checking if the fork still matches the route we want to load at the end of the navigation. At that point it could've changed, or it could never have matched (as in the related issue). Fixes #14946

.changeset/dull-spies-hammer.md [new file with mode: 0644]
packages/kit/src/runtime/client/client.js
packages/kit/test/apps/basics/src/routes/data-sveltekit/preload-data/offline/slow-navigation/+page.svelte
packages/kit/test/apps/basics/src/routes/data-sveltekit/preload-data/offline/target/+page.svelte
packages/kit/test/apps/basics/test/client.test.js

diff --git a/.changeset/dull-spies-hammer.md b/.changeset/dull-spies-hammer.md
new file mode 100644 (file)
index 0000000..119795f
--- /dev/null
@@ -0,0 +1,5 @@
+---
+'@sveltejs/kit': patch
+---
+
+fix: don't use fork of unrelated route
index b04664ddc578985644189d444057dad0ed99fe22..f071649309837268e6bc9cd58cb64f3cac1acb01 100644 (file)
@@ -1690,8 +1690,9 @@ async function navigate({
                }
        }
 
+       // also compare ids to avoid using wrong fork (e.g. a new one could've been added while navigating)
+       const load_cache_fork = intent && load_cache?.id === intent.id ? load_cache.fork : null;
        // reset preload synchronously after the history state has been set to avoid race conditions
-       const load_cache_fork = load_cache?.fork;
        load_cache = null;
 
        navigation_result.props.page.state = state;
index 059e3afed201d394d18dd060a769bc09fbb7be69..f551432d81f864730182e291d8d451badb382113 100644 (file)
@@ -1047,6 +1047,21 @@ test.describe('data-sveltekit attributes', () => {
                expect(page).toHaveURL('/data-sveltekit/preload-data/offline/slow-navigation');
        });
 
+       test('data-sveltekit-preload does not abort ongoing navigation #2', async ({ page }) => {
+               await page.goto('/data-sveltekit/preload-data/offline');
+
+               await page.locator('#slow-navigation').dispatchEvent('click');
+               await page.waitForTimeout(100); // wait for navigation to start
+               await page.locator('#one').dispatchEvent('mousemove');
+               await Promise.all([
+                       page.waitForTimeout(100), // wait for preloading to start
+                       page.waitForLoadState('networkidle') // wait for preloading to finish
+               ]);
+
+               expect(page).toHaveURL('/data-sveltekit/preload-data/offline/slow-navigation');
+               await expect(page.getByText('slow navigation', { exact: true })).toBeVisible();
+       });
+
        test('data-sveltekit-preload-data tap works after data-sveltekit-preload-code hover', async ({
                page
        }) => {