{"record":{"id":"1d91811b594ea433","repo":"sveltejs/svelte","slug":"effect-update-depth-exceeded","errorCode":"effect_update_depth_exceeded","errorMessage":"effect_update_depth_exceeded\nMaximum update depth exceeded. This typically indicates that an effect reads and writes the same piece of state\nhttps://svelte.dev/e/effect_update_depth_exceeded","messagePattern":"effect_update_depth_exceeded\nMaximum update depth exceeded\\. This typically indicates that an effect reads and writes the same piece of state\nhttps://svelte\\.dev/e/effect_update_depth_exceeded","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"packages/svelte/src/internal/client/errors.js","lineNumber":247,"sourceCode":"\t\tthrow error;\n\t} else {\n\t\tthrow new Error(`https://svelte.dev/e/effect_pending_outside_reaction`);\n\t}\n}\n\n/**\n * Maximum update depth exceeded. This typically indicates that an effect reads and writes the same piece of state\n * @returns {never}\n */\nexport function effect_update_depth_exceeded() {\n\tif (DEV) {\n\t\tconst error = new Error(`effect_update_depth_exceeded\\nMaximum update depth exceeded. This typically indicates that an effect reads and writes the same piece of state\\nhttps://svelte.dev/e/effect_update_depth_exceeded`);\n\n\t\terror.name = 'Svelte error';\n\n\t\tthrow error;\n\t} else {\n\t\tthrow new Error(`https://svelte.dev/e/effect_update_depth_exceeded`);\n\t}\n}\n\n/**\n * Cannot use `flushSync` inside an effect\n * @returns {never}\n */\nexport function flush_sync_in_effect() {\n\tif (DEV) {\n\t\tconst error = new Error(`flush_sync_in_effect\\nCannot use \\`flushSync\\` inside an effect\\nhttps://svelte.dev/e/flush_sync_in_effect`);\n\n\t\terror.name = 'Svelte error';\n\n\t\tthrow error;\n\t} else {\n\t\tthrow new Error(`https://svelte.dev/e/flush_sync_in_effect`);\n\t}\n}","sourceCodeStart":229,"sourceCodeEnd":265,"githubUrl":"https://github.com/sveltejs/svelte/blob/20b341f10048cf1016a2028ac7eee5595cfef6a5/packages/svelte/src/internal/client/errors.js#L229-L265","documentation":"Thrown by infinite_loop_guard() in reactivity/batch.js:1067 after the batch flush loop exceeds Svelte's maximum update iteration count. The guard exists because effects that synchronously read and then write the same state re-trigger themselves forever; rather than freeze the browser Svelte aborts and routes the error to the nearest boundary (batch.js:1066-1077).","triggerScenarios":"A $effect whose body both reads a $state/$derived and synchronously writes to it (or to a dependency that feeds back), causing the effect to reschedule on every flush. Also: mutual effects that re-trigger each other, or setting state unconditionally inside an effect callback.","commonSituations":"Writing `let count = $state(0); $effect(() => { count = count + 1; })`; updating a store a component subscribes to inside an effect that reads it; cascading effects where A writes B and B writes A; forgetting a condition guard so a 'last updated' timestamp always fires.","solutions":["Remove the synchronous write from the effect — move it to an event handler so the state change is user-driven, not reactive.","Guard the write with a condition so it only runs when the value actually changes (e.g. `if (x !== next) x = next`).","Split the logic: use $derived for the computed value instead of $effect + state write.","Use untrack(() => {...}) around the write if you intentionally want to break the reactive dependency, though restructuring is preferred."],"exampleFix":"// before\nlet count = $state(0);\n$effect(() => { count = count + 1; }); // infinite loop\n\n// after — derive instead of effect+write\nlet count = $state(0);\nlet doubled = $derived(count * 2);\n// or move the increment to a user action\nfunction increment() { count += 1; }","handlingStrategy":"try-catch","validationCode":"// Before shipping, audit each $effect: ensure it does not synchronously write\n// to any $state/$derived it also reads.\n// Quick static check pattern:\nfunction assertEffectNotCyclic(stateWrites, stateReads) {\n  const overlap = stateWrites.filter(k => stateReads.includes(k));\n  if (overlap.length) throw new Error('Effect writes and reads: ' + overlap.join(', '));\n}","typeGuard":null,"tryCatchPattern":"// Wrap state writes in effects with a change guard to prevent self-retrigger:\n$effect(() => {\n  const next = compute(data);\n  if (next !== cached) { cached = next; stateVar = next; }\n});\n// For robustness against runaway loops, you may also catch in an error boundary:\n// <svelte:boundary onerror={(e) => logCyclicError(e)}>...</svelte:boundary>","preventionTips":["Prefer $derived over $effect-plus-state-write for computed values.","Inside $effect, only write state in response to external events (user input, timers), never unconditionally.","Add an inequality guard before any write inside an effect.","Use Svelte DevTools to see which effects re-run and why."],"tags":["svelte","runes","effects","reactivity","infinite-loop","performance"],"backgroundTag":null,"analyzedSha":"20b341f10048cf1016a2028ac7eee5595cfef6a5","analyzedAt":"2026-08-12T23:37:30.399Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}