sveltejs/svelte · error · Error
fork_discarded
fork_discarded
Error message
fork_discarded Cannot commit a fork that was already discarded https://svelte.dev/e/fork_discarded
What it means
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.
Source
Thrown at packages/svelte/src/internal/client/errors.js:279
throw error;
} else {
throw new Error(`https://svelte.dev/e/flush_sync_in_effect`);
}
}
/**
* Cannot commit a fork that was already discarded
* @returns {never}
*/
export function fork_discarded() {
if (DEV) {
const error = new Error(`fork_discarded\nCannot commit a fork that was already discarded\nhttps://svelte.dev/e/fork_discarded`);
error.name = 'Svelte error';
throw error;
} else {
throw new Error(`https://svelte.dev/e/fork_discarded`);
}
}
/**
* Cannot create a fork inside an effect or when state changes are pending
* @returns {never}
*/
export function fork_timing() {
if (DEV) {
const error = new Error(`fork_timing\nCannot create a fork inside an effect or when state changes are pending\nhttps://svelte.dev/e/fork_timing`);
error.name = 'Svelte error';
throw error;
} else {
throw new Error(`https://svelte.dev/e/fork_timing`);
}
}View on GitHub (pinned to 20b341f100)
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.
Example fix
// before
const f = fork(() => { ... });
f.discard();
await f.commit(); // throws
// after
const f = fork(() => { ... });
let active = true;
// on navigation: active = false; f.discard();
async function maybeCommit() {
if (!active) return;
try { await f.commit(); }
catch (e) { /* fork already discarded */ }
} Defensive patterns
Strategy: try-catch
Validate before calling
// Track fork lifecycle explicitly before committing.
let forkActive = true;
const f = fork(() => { ... });
function discardFork() { forkActive = false; f.discard(); }
async function commitFork() {
if (!forkActive) return;
try { await f.commit(); }
catch (e) { if (!forkActive) return; throw e; }
} Try / catch
try {
await f.commit();
} catch (e) {
if (e?.message?.includes('fork_discarded') || e?.message?.includes('svelte.dev/e/fork_discarded')) {
// fork already discarded — ignore
} else { throw e; }
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- fork_timing
- hydratable_missing_but_required
- state_unsafe_mutation
- effect_in_unowned_derived
- effect_orphan
AI-assisted analysis of sveltejs/svelte@20b341f100 (2026-08-12).
Data as JSON: /api/errors/16f24c7538e85a33.
Report an issue: GitHub.