{"record":{"id":"16f24c7538e85a33","repo":"sveltejs/svelte","slug":"fork-discarded","errorCode":"fork_discarded","errorMessage":"fork_discarded\nCannot commit a fork that was already discarded\nhttps://svelte.dev/e/fork_discarded","messagePattern":"fork_discarded\nCannot commit a fork that was already discarded\nhttps://svelte\\.dev/e/fork_discarded","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/svelte/src/internal/client/errors.js","lineNumber":279,"sourceCode":"\t\tthrow error;\n\t} else {\n\t\tthrow new Error(`https://svelte.dev/e/flush_sync_in_effect`);\n\t}\n}\n\n/**\n * Cannot commit a fork that was already discarded\n * @returns {never}\n */\nexport function fork_discarded() {\n\tif (DEV) {\n\t\tconst error = new Error(`fork_discarded\\nCannot commit a fork that was already discarded\\nhttps://svelte.dev/e/fork_discarded`);\n\n\t\terror.name = 'Svelte error';\n\n\t\tthrow error;\n\t} else {\n\t\tthrow new Error(`https://svelte.dev/e/fork_discarded`);\n\t}\n}\n\n/**\n * Cannot create a fork inside an effect or when state changes are pending\n * @returns {never}\n */\nexport function fork_timing() {\n\tif (DEV) {\n\t\tconst error = new Error(`fork_timing\\nCannot create a fork inside an effect or when state changes are pending\\nhttps://svelte.dev/e/fork_timing`);\n\n\t\terror.name = 'Svelte error';\n\n\t\tthrow error;\n\t} else {\n\t\tthrow new Error(`https://svelte.dev/e/fork_timing`);\n\t}\n}","sourceCodeStart":261,"sourceCodeEnd":297,"githubUrl":"https://github.com/sveltejs/svelte/blob/20b341f10048cf1016a2028ac7eee5595cfef6a5/packages/svelte/src/internal/client/errors.js#L261-L297","documentation":"Thrown at reactivity/batch.js:1401 inside a fork's commit() when batch.linked is false, meaning the fork has already been discarded. A fork created via the experimental fork() API holds speculative state; once discard() runs (e.g. because navigation moved elsewhere) the fork is unlinked from the main state graph and committing it would lose data integrity.","triggerScenarios":"Calling fork().commit() after fork().discard() was already invoked, or after the fork was auto-discarded by a navigation/route change. The guard at batch.js:1400-1402 checks batch.linked.","commonSituations":"Optimistic-update forks in routing where the user navigates away then a stale promise resolves and tries to commit; holding a fork reference in a long-lived cache and committing after cleanup; race between discard and an in-flight async commit.","solutions":["Track fork lifecycle explicitly and guard commit() behind an `if (!discarded)` flag you own.","Call discard() only after you are certain no commit will follow, or cancel in-flight commits first.","Use try/catch around commit() to tolerate races and log/handle the stale fork."],"exampleFix":"// before\nconst f = fork(() => { ... });\nf.discard();\nawait f.commit(); // throws\n\n// after\nconst f = fork(() => { ... });\nlet active = true;\n// on navigation: active = false; f.discard();\nasync function maybeCommit() {\n  if (!active) return;\n  try { await f.commit(); }\n  catch (e) { /* fork already discarded */ }\n}","handlingStrategy":"try-catch","validationCode":"// Track fork lifecycle explicitly before committing.\nlet forkActive = true;\nconst f = fork(() => { ... });\nfunction discardFork() { forkActive = false; f.discard(); }\nasync function commitFork() {\n  if (!forkActive) return;\n  try { await f.commit(); }\n  catch (e) { if (!forkActive) return; throw e; }\n}","typeGuard":null,"tryCatchPattern":"try {\n  await f.commit();\n} catch (e) {\n  if (e?.message?.includes('fork_discarded') || e?.message?.includes('svelte.dev/e/fork_discarded')) {\n    // fork already discarded — ignore\n  } else { throw e; }\n}","preventionTips":["Treat forks as single-use: either commit or discard, never both.","Set a flag when discarding and check it before committing.","Cancel in-flight async work before discarding a fork."],"tags":["svelte","fork","experimental","async","state","reactivity"],"backgroundTag":null,"analyzedSha":"20b341f10048cf1016a2028ac7eee5595cfef6a5","analyzedAt":"2026-08-12T23:37:30.399Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}