On this page

AsyncEffectInSyncRuneError

Trace effect work found in a Svelte rune position with a synchronous contract.

What this error means and what can trigger it

AsyncEffectInSyncRuneError means SER found yield* inside a Svelte rune position that it cannot turn into dispatcher work without changing the rune's semantics. The error records the rune name, complete expression text, and source filename.

There are two ways to reach it. One is to place effect work in a rune outside SER's small set of async-expression-compatible runes. At present, that set contains $derived, $state, $state.raw, $state.snapshot, and $bindable; calls such as $props(yield* Load()), $effect.pending(yield* Load()), or $inspect(yield* Load()) therefore fail the general check.

The other route goes through the first callback passed to $derived.by, $effect, $effect.pre, or $effect.root. Although the general detector stops at that callback's function boundary, SER opens it separately and rejects a direct yield* inside.

Exactly where it triggers

Unsupported rune argument:

if (!ASYNC_EXPRESSION_RUNES.has(rune_name) && contains_top_level_yield_star(call)) {
	throw new AsyncEffectInSyncRuneError(rune_name, slice(content, call), filename);
}

Synchronous rune callback:

if (!CALLBACK_RUNES.has(rune_name)) {
	return;
}

const callback = call.arguments[0];

if (!callback || !callback_has_top_level_yield_star(callback)) {
	return;
}

throw new AsyncEffectInSyncRuneError(rune_name, slice(content, call), filename);

Both are synchronous transform exceptions. For reference, the class itself is declared at modules/svelte-effect-runtime/src/errors.ts L169 @ C14.

Why this is the case

Svelte assigns specific compile-time and runtime contracts to each rune. An effect callback participates in Svelte's lifecycle; a derived callback computes synchronously; props, host, and inspection helpers have compiler-defined return behavior. Replacing one of those expressions with a value that resolves later would alter the rune itself.

SER only lowers rune positions for which it has an explicit value-preserving transformation. A callback is checked separately because its function boundary hides its body from the normal top-level scan.