sveltejs/kit · warning
Avoid using `history.pushState(...)` and `history.replaceSta
Error message
Avoid using `history.pushState(...)` and `history.replaceState(...)` as these will conflict with SvelteKit's router. Use `goto(...)` from `$app/navigation` instead.
What it means
SvelteKit's client-side router takes ownership of the History API; calling the raw `history.pushState()`/`history.replaceState()` directly bypasses the router and desynchronizes navigation state. The router monkey-patches these methods and warns once when an app (outside node_modules) calls them, suggesting `goto()` instead.
Source
Thrown at packages/kit/src/runtime/client/client.js:139
if (warned) return;
// Rather than saving a pointer to the original history methods, which would prevent monkeypatching by other libs,
// inspect the stack trace to see if we're being called from within SvelteKit.
let stack = new Error().stack?.split('\n');
if (!stack) return;
if (!stack[0].includes('https:') && !stack[0].includes('http:')) stack = stack.slice(1); // Chrome includes the error message in the stack
// skip over `warn` and the place where `warn` was called
const frame = stack[2];
// Ignore calls that happen inside dependencies, including SvelteKit.
// The second condition is only relevant when developing SvelteKit and running it, as there's no node_modules in the stack then (but we still do it to not get repeatedly confused)
// `frame` can be falsy if we came from an anonymous function
if (frame?.includes('node_modules') || frame?.includes(current_module_url)) return;
warned = true;
console.warn(
"Avoid using `history.pushState(...)` and `history.replaceState(...)` as these will conflict with SvelteKit's router. Use `goto(...)` from `$app/navigation` instead."
);
};
const push_state = history.pushState;
history.pushState = (...args) => {
warn();
return push_state.apply(history, args);
};
const replace_state = history.replaceState;
history.replaceState = (...args) => {
warn();
return replace_state.apply(history, args);
};
}
/** @param {number} index */View on GitHub (pinned to 03f1687fe6)
Solutions
- Replace `history.pushState(state, '', url)` with `goto(url, { state })` from `$app/navigation`
- Replace `history.replaceState(state, '', url)` with `goto(url, { replace: true, state })`
- Use the `$app/state`/`navigating` stores or `beforeNavigate` if you need URL state tied to SvelteKit's router state
Example fix
// before
history.pushState({ tab: 'settings' }, '', '/settings');
// after
import { goto } from '$app/navigation';
goto('/settings', { state: { tab: 'settings' } }); Defensive patterns
Strategy: fallback
Validate before calling
// ensure navigation goes through the router
function appPush(url, state) { return goto(url, { state }); } Type guard
function isHistoryCall(fn) { return fn === history.pushState || fn === history.replaceState; } Try / catch
try { await goto(url, { state }); } catch (e) { console.error('navigation failed', e); } Prevention
- Use `goto`/`replaceState` option from `$app/navigation` for all URL changes
- Audit third-party scripts that manipulate history
- Use `beforeNavigate`/`afterNavigate` hooks instead of history listeners
When it happens
Trigger: Calling `history.pushState(state, '', url)` or `history.replaceState(...)` in app code (component, action, library bundled into the app) after the SvelteKit router has started; the patched method in packages/kit/src/runtime/client/client.js warns once unless the call comes from node_modules or SvelteKit itself.
Common situations: Tabs/modals/URL-state sync code written with plain History API; third-party widgets integrating history directly; porting a vanilla SPA page into SvelteKit.
Related errors
- The "${lookup.get(key)}" and "${route.id}" routes conflict w
- '${id}' has no `+page`, so there is no code to preload. If y
- '${id}' did not match any route (note that routes without a
- Cannot build with ${JSON.stringify(file)} because Bun treats
- Cannot build with ${JSON.stringify(file)} because Bun treats
AI-assisted analysis of sveltejs/kit@03f1687fe6 (2026-09-02).
Data as JSON: /api/errors/ed4889f5e9892494.
Report an issue: GitHub.