Repository navigation
forkPreloads: after a preloaded navigation to the same route commits, a top-level await keeps the old URL's result #17438
Description
Describe the bug
With experimental.forkPreloads, a navigation to the same route with different search params shows the new URL, but the page keeps the data it showed for the old URL.
The page reads the URL and awaits a remote query at the top level of its script:
const date = $derived(page.url.searchParams.get('date') ?? '2026-01-05');
const week = $derived(await getWeek(date));
const next = $derived(`?date=${addDays(date, 7)}`);Hovering the "Next" link preloads ?date=2026-01-12 in a fork, and getWeek('2026-01-12') is requested. Clicking the link commits that navigation: the address bar and page.url.search show ?date=2026-01-12, but week still holds the result for 2026-01-05, so the page shows the old week until the next navigation. No error is logged.
If the navigation is made with goto(next) from a button instead of the link, next keeps its old value too (?date=2026-01-12, the URL we are already on), even though the template's page.url.search is new. So the "Next" button has to be pressed twice to move one week.
With forkPreloads off, the same steps show the new week every time.
Reproduction
https://github.com/xyrolle/sveltekit-fork-preloads-same-route at 51bcdec (pnpm install --frozen-lockfile, pnpm exec playwright install chromium, pnpm build, pnpm probe; versions pinned). The relevant files:
// vite.config.ts: `pnpm build` builds build-on (forkPreloads on) and build-off (FORK=0)
import adapter from '@sveltejs/adapter-node';
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
const forkPreloads = process.env.FORK !== '0';
export default defineConfig({
plugins: [
sveltekit({
adapter: adapter({ out: forkPreloads ? 'build-on' : 'build-off' }),
compilerOptions: { experimental: { async: true } },
experimental: { remoteFunctions: true, forkPreloads }
})
]
});<!-- src/app.html: the body has data-sveltekit-preload-data="hover" -->
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div>%sveltekit.body%</div>
</body>
</html>// src/routes/week/data.remote.ts
import { query } from '$app/server';
export const getWeek = query('unchecked', async (date: string) => {
await new Promise((resolve) => setTimeout(resolve, 300));
return { date };
});<!-- src/routes/week/+page.svelte -->
<script lang="ts">
import { goto } from '$app/navigation';
import { page } from '$app/state';
import { getWeek } from './data.remote.ts';
const addDays = (date: string, days: number) =>
new Date(Date.parse(`${date}T00:00:00Z`) + days * 86_400_000).toISOString().slice(0, 10);
const date = $derived(page.url.searchParams.get('date') ?? '2026-01-05');
const week = $derived(await getWeek(date));
const next = $derived(`?date=${addDays(date, 7)}`);
</script>
<h1>{week.date}</h1>
<p>{page.url.search}</p>
<a href={next}>Next</a>
<button onclick={() => goto(next)}>Next (goto)</button>Steps: pnpm build, then node build-on, open http://localhost:3000/week?date=2026-01-05, rest the pointer on "Next" for a second, then click it (or click "Next (goto)"). For comparison, node build-off serves the same app with forkPreloads off.
Expected: the heading shows 2026-01-12, and "Next" links to ?date=2026-01-19.
Actual: the address bar and the <p> show ?date=2026-01-12, the heading still shows 2026-01-05. After "Next (goto)", "Next" also still links to ?date=2026-01-12.
pnpm probe (Playwright, headless Chromium, node build-on / node build-off), 10 loads each. It waits until the address bar and the page's page.url.search line both show ?date=2026-01-12, gives the heading two seconds, and counts the heading still showing exactly 2026-01-05:
| old week shown | "Next" still ?date=2026-01-12 |
|
|---|---|---|
| forkPreloads on, link click | 10/10 | 0/10 |
forkPreloads on, goto |
10/10 | 10/10 |
| forkPreloads off, link click | 0/10 | 0/10 |
forkPreloads off, goto |
0/10 | 0/10 |
With Svelte built from main (86eb09b76) it is the same. With Svelte built from sveltejs/svelte#18988 (head 8a1046e42) both rows with forkPreloads on go to 0/5, so the cause may be in how Svelte commits a fork. sveltejs/svelte#18988 has since been merged into async-another-try-pt-2, not main; that branch is part of sveltejs/svelte#18880, which is still open (retest below).
Logs
No errors in the browser console or the server output.System Info
System:
OS: macOS 27.2
CPU: (18) arm64 Apple M5 Pro
Binaries:
Node: 24.16.0
Browsers:
Chromium 153.0.8010.12 (Playwright 1.63.0)
npmPackages:
@sveltejs/adapter-node: 6.0.0
@sveltejs/kit: 3.0.1
@sveltejs/vite-plugin-svelte: 7.3.1
svelte: 5.57.2
vite: 8.3.4Severity
annoyance
Additional Information
The hover also requests getWeek('2026-01-12') twice; that part is #15807 / #17370.
#14996 also goes away without forkPreloads, but there page.params is read inside the async function passed to $derived(await ...), after an await, and the fix suggested there is to pass it in as an argument. Here the argument already is: date is a plain $derived of page.url, read before the await.
Activity
svelte-triage-bot commentedon Oct 14, 2026
I reproduced the issue, but could not produce a safe, verified fix.
What I tried
forkPreloads: after a preloaded navigation to the same route commits, a top-levelawaitkeeps the old URL's result #17438 and comments through the github connection; read repository guidance and forkPreloads API documentation.: Confirmed the current report and reproduction. No issue comments or documented limitation excluding same-route query-parameter navigation.Why I stopped
An existing open PR already fixes the reproduced bug: sveltejs/svelte#18988. Its exact head fixes both reported navigation paths in the supplied app without any Kit product change. Stopping under the open-PR prior-art rule rather than proposing a competing workaround. This is not a non-reproduction: current Kit with released Svelte fails reliably. A Kit integration regression covering both link and goto navigation can follow once the upstream Svelte fix lands.
xyrolle commentedon Oct 22, 2026
Retested the reproduction with Kit 3.0.1 and everything else unchanged, against
packages/sveltefrom two Svelte commits:goto: old weekgoto: "Next" still?date=2026-01-12main(2334f5e)With
forkPreloadsoff, every count is 0/5 on both, and every run reportsother: none; errors: none.sveltejs/svelte#18988, which fixed this in the report, has since been merged into sveltejs/svelte#18880 (through sveltejs/svelte#18881), which is still open. With Kit unchanged, the reproduction passes at that PR's head, so I'm not proposing a Kit change. Once a Svelte release passes it, I'm happy to add a Kit test for both the link and
gotonavigations.Commands and output
pnpm 11.28.3, Node 24.16.0, Chromium from Playwright 1.63.0, macOS.