Skip to content

snapshot() helper does not restore on reload when ssr is disabled #17476

Closed

Description

@teemingc

Describe the bug

When ssr is disabled, state captured with the new snapshot() helper from $app/navigation is not restored after a page reload. The value is persisted to sessionStorage (under sveltekit:navigation-snapshot) but restore is never called.

The deprecated export const snapshot restores correctly on the same kind of page, and the snapshot() helper restores correctly on reload when the page is server-rendered (covered by the existing persists function snapshots with transport support test).

Reproduction

// src/routes/+layout.js
export const ssr = false;
<!-- src/routes/+page.svelte -->
<script>
	import { snapshot } from '$app/navigation';

	let message = $state('');

	snapshot({
		id: 'message',
		capture: () => message,
		restore: (value) => (message = value)
	});
</script>

<input bind:value={message} />
  1. Type something into the input
  2. Reload the page
  3. The input is empty

added to packages/kit/test/apps/basics under the existing /no-ssr layout:

test('restores exported snapshots on reload when ssr is disabled', async ({ page }) => {
	await page.goto('/no-ssr/snapshot/export');
	await page.locator('input').fill('reload value');
	await page.reload();
	await expect(page.locator('input')).toHaveValue('reload value'); // passes
});

test('restores function snapshots on reload when ssr is disabled', async ({ page }) => {
	await page.goto('/no-ssr/snapshot/helper');
	await page.locator('input').fill('reload value');
	await page.reload();
	await expect(page.locator('input')).toHaveValue('reload value'); // fails: received ""
});

Logs

Error: expect(locator).toHaveValue(expected) failed
Expected: "reload value"
Received: ""

System Info

System:
  OS: macOS 27.2
  CPU: (8) arm64 Apple M1 Pro
Binaries:
  Node: 24.22.0
  pnpm: 12.11.2
npmPackages:
  @sveltejs/kit: 3.1.0 (main @ 73bf98cab)
  @sveltejs/vite-plugin-svelte: 7.3.1
  svelte: 5.57.1
  vite: 8.3.0

Severity

serious, but I can work around it

Additional Information

Workaround: keep using the deprecated export const snapshot.

From instrumenting the client runtime: on reload with ssr = false, the helper's onMount registration runs while the initial client-side navigation is still in progress (started is false, is_navigating/updating are true), so get_idle_history_index() returns null and the helper skips restoring there. The restore_navigation_snapshot(current_history_index) call at the end of initialize also doesn't invoke the callback, even though the persisted entry for that history index is in sessionStorage. I haven't pinned down why the second path misses it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions