sveltejs/svelte · error · Error

effect_in_teardown

effect_in_teardown

Error message

effect_in_teardown
`${rune}` cannot be used inside an effect cleanup function
https://svelte.dev/e/effect_in_teardown

What it means

Runtime error `effect_in_teardown`: a Svelte 5 rune (`$effect`, `$pre_effect`, or `$derived`) was used inside an effect cleanup (teardown) function. Effects and deriveds must be created during the setup phase of an owner effect, not during cleanup, because teardowns run in an unowned context. The message names the offending rune.

Source

Thrown at packages/svelte/src/internal/client/errors.js:182

	} else {
		throw new Error(`https://svelte.dev/e/each_key_volatile`);
	}
}

/**
 * `%rune%` cannot be used inside an effect cleanup function
 * @param {string} rune
 * @returns {never}
 */
export function effect_in_teardown(rune) {
	if (DEV) {
		const error = new Error(`effect_in_teardown\n\`${rune}\` cannot be used inside an effect cleanup function\nhttps://svelte.dev/e/effect_in_teardown`);

		error.name = 'Svelte error';

		throw error;
	} else {
		throw new Error(`https://svelte.dev/e/effect_in_teardown`);
	}
}

/**
 * Effect cannot be created inside a `$derived` value that was not itself created inside an effect
 * @returns {never}
 */
export function effect_in_unowned_derived() {
	if (DEV) {
		const error = new Error(`effect_in_unowned_derived\nEffect cannot be created inside a \`$derived\` value that was not itself created inside an effect\nhttps://svelte.dev/e/effect_in_unowned_derived`);

		error.name = 'Svelte error';

		throw error;
	} else {
		throw new Error(`https://svelte.dev/e/effect_in_unowned_derived`);
	}
}

View on GitHub (pinned to 20b341f100)

Solutions

  1. Move the `$effect`/`$derived` creation out of the cleanup and into the effect body (the setup phase).
  2. For cleanup-only work, do plain imperative teardown (clear timers, remove listeners) without using runes.
  3. If you need a derived that lives across the effect lifetime, declare it at component scope, not inside the cleanup.

Example fix

// before
$effect(() => {
  return () => {
    $effect(() => { /* ... */ }); // teardown starting an effect
  };
});

// after
$effect(() => {
  // setup runs here
  $effect(() => { /* ... */ });
  return () => {
    // cleanup: only plain imperative teardown, no runes
  };
});
Defensive patterns

Strategy: validation

Validate before calling

// Detect rune usage inside an $effect cleanup return.
function runeInTeardown(source) {
  // crude: finds `$effect(() => { ... return () => { $effect(...)/$derived(...) } })`
  return /return\s*\(\s*\(?\)\s*=>\s*\{[\s\S]*?\$(?:effect|derived|pre_effect)\(/.test(source);
}

Prevention

When it happens

Trigger: At runtime (DEV) when the body of an `$effect` cleanup callback (the function returned from the effect, or registered via `$.onDestroy`-style APIs) calls `$effect(...)`, `$derived(...)`, or another lifecycle rune.

Common situations: Migrating Svelte 4 `onDestroy(() => { ... })` callbacks that set up new reactive computations; cleanup functions that try to subscribe to a store or start a timer-driven effect; refactoring that moved setup logic into teardown by mistake.

Related errors


AI-assisted analysis of sveltejs/svelte@20b341f100 (2026-08-12). Data as JSON: /api/errors/9728b58ecfe9e864. Report an issue: GitHub.