sveltejs/kit · error

Cannot call ${caller}(...) before router is initialized

Error message

Cannot call ${caller}(...) before router is initialized

What it means

update_state() backs goto(), pushState() and replaceState(). If the router has not started yet (the `started` flag is false, DEV only), calling any of these throws because there is no router state to update. Navigation APIs are only valid after hydration/initialization completes.

Source

Thrown at packages/kit/src/runtime/client/client.js:2968

		intent,
		state,
		{ replace: true, persist_state: false, reset: false },
		'replaceState'
	);
}

/**
 * @param {NavigationIntent} intent
 * @param {App.PageState} state
 * @param {{ replace: boolean; persist_state: boolean; reset: boolean; }} options
 * @param {'goto' | 'pushState' | 'replaceState'} caller
 */
async function update_state(intent, state, { replace, persist_state, reset }, caller) {
	const url = intent.url;
	const previous_snapshot_registrations = current_registrations();

	if (DEV && !started) {
		throw new Error(`Cannot call ${caller}(...) before router is initialized`);
	}

	const nav =
		// For backwards compatibility we don't trigger navigation hooks etc for push/replaceState
		caller === 'goto' ? _before_navigate({ url, type: 'goto', intent, shallow: true }) : undefined;

	if (!nav && caller === 'goto') return;

	const nav_token = {};

	if (nav) {
		navigation_token = invalidation_token = nav_token;
		is_navigating = true;
		set_navigation(nav.navigation);
		updating = true;
	}

	if (replace) {

View on GitHub (pinned to 03f1687fe6)

Solutions

  1. Move the call into onMount or after the app/router has started
  2. Use $app/stores page state instead of navigating during init
  3. Gate the call on the router being ready (e.g. afterMount flag)

Example fix

// before
// +page.svelte module scope
const id = page.params.id;
if (!id) goto('/');
// after
import { onMount } from 'svelte';
onMount(() => { if (!page.params.id) goto('/'); });
Defensive patterns

Strategy: validation

Validate before calling

let routerReady = false;
// set routerReady = true in onMount of your root layout
function safeGoto(...args) {
  if (!routerReady) return;
  return goto(...args);
}

Try / catch

try { await goto('/'); } catch (e) { if (e.message.includes('before router is initialized')) { /* defer */ } else { throw e; } }

Prevention

When it happens

Trigger: Calling goto/pushState/replaceState at module top level of a +page.svelte or in a store initializer that runs before the client router starts; calling during SSR-adjacent early module evaluation.

Common situations: Top-level side effects in components; initializing state from a URL in module scope; invoking navigation from imported module bodies rather than lifecycle callbacks.

Related errors


AI-assisted analysis of sveltejs/kit@03f1687fe6 (2026-09-02). Data as JSON: /api/errors/14748c4974983965. Report an issue: GitHub.