{"record":{"id":"ed4889f5e9892494","repo":"sveltejs/kit","slug":"avoid-using-history-pushstate-and-history","errorCode":null,"errorMessage":"Avoid using `history.pushState(...)` and `history.replaceState(...)` as these will conflict with SvelteKit's router. Use `goto(...)` from `$app/navigation` instead.","messagePattern":"Avoid using `history\\.pushState\\(\\.\\.\\.\\)` and `history\\.replaceState\\(\\.\\.\\.\\)` as these will conflict with SvelteKit's router\\. Use `goto\\(\\.\\.\\.\\)` from `\\$app/navigation` instead\\.","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/kit/src/runtime/client/client.js","lineNumber":139,"sourceCode":"\t\tif (warned) return;\n\n\t\t// Rather than saving a pointer to the original history methods, which would prevent monkeypatching by other libs,\n\t\t// inspect the stack trace to see if we're being called from within SvelteKit.\n\t\tlet stack = new Error().stack?.split('\\n');\n\t\tif (!stack) return;\n\t\tif (!stack[0].includes('https:') && !stack[0].includes('http:')) stack = stack.slice(1); // Chrome includes the error message in the stack\n\n\t\t// skip over `warn` and the place where `warn` was called\n\t\tconst frame = stack[2];\n\n\t\t// Ignore calls that happen inside dependencies, including SvelteKit.\n\t\t// 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)\n\t\t// `frame` can be falsy if we came from an anonymous function\n\t\tif (frame?.includes('node_modules') || frame?.includes(current_module_url)) return;\n\n\t\twarned = true;\n\n\t\tconsole.warn(\n\t\t\t\"Avoid using `history.pushState(...)` and `history.replaceState(...)` as these will conflict with SvelteKit's router. Use `goto(...)` from `$app/navigation` instead.\"\n\t\t);\n\t};\n\n\tconst push_state = history.pushState;\n\thistory.pushState = (...args) => {\n\t\twarn();\n\t\treturn push_state.apply(history, args);\n\t};\n\n\tconst replace_state = history.replaceState;\n\thistory.replaceState = (...args) => {\n\t\twarn();\n\t\treturn replace_state.apply(history, args);\n\t};\n}\n\n/** @param {number} index */","sourceCodeStart":121,"sourceCodeEnd":157,"githubUrl":"https://github.com/sveltejs/kit/blob/03f1687fe612ce3d2d9131139b5b188d9cf90c64/packages/kit/src/runtime/client/client.js#L121-L157","documentation":"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.","triggerScenarios":"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.","commonSituations":"Tabs/modals/URL-state sync code written with plain History API; third-party widgets integrating history directly; porting a vanilla SPA page into SvelteKit.","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"],"exampleFix":"// before\nhistory.pushState({ tab: 'settings' }, '', '/settings');\n// after\nimport { goto } from '$app/navigation';\ngoto('/settings', { state: { tab: 'settings' } });","handlingStrategy":"fallback","validationCode":"// ensure navigation goes through the router\nfunction appPush(url, state) { return goto(url, { state }); }","typeGuard":"function isHistoryCall(fn) { return fn === history.pushState || fn === history.replaceState; }","tryCatchPattern":"try { await goto(url, { state }); } catch (e) { console.error('navigation failed', e); }","preventionTips":["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"],"tags":["routing","history-api","client-side","conflict"],"backgroundTag":"history-pushstate-conflict","analyzedSha":"03f1687fe612ce3d2d9131139b5b188d9cf90c64","analyzedAt":"2026-09-02T02:01:50.504Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T06:17:21.866Z"}