On this page

AsyncEffectInEventCallbackError

Trace yield work hidden inside a nested synchronous callback in an event expression.

What this error means and what can trigger it

AsyncEffectInEventCallbackError means the event expression begins at a valid SER boundary, but another yield* is still buried inside a nested non-generator callback. For example: onclick={yield* Effect.try(() => yield* Save())}.

SER parses the event body in a synthetic generator and tracks whether each yield* belongs to the top-level event body, a nested generator, or an invalid nested function. Arrows, ordinary functions, methods, getters, and setters enter the invalid context. Generator functions enter a separate valid generator context.

SER can normalize known Effect combinators into generator-safe forms before it performs this check. If nested work remains, however, the transform stops. This includes yielding callbacks attached to receivers whose invocation semantics SER cannot prove.

Exactly where it triggers

const analysis = analyze_event_body_yield_star(expr_text);

if (analysis.has_nested_invalid_yield_star) {
	throw new AsyncEffectInEventCallbackError(candidate.filename, expr_text);
}

The callback-shaped whole-expression check runs first. This second check therefore addresses nested callback boundaries inside an otherwise direct event expression. It throws synchronously during the markup transform. For reference, the class itself is declared at modules/svelte-effect-runtime/src/errors.ts L222 @ C14.

Why this is the case

Moving a yield* out of an arbitrary callback could change when the callback runs, how many times it runs, which arguments it receives, what it returns, and how thrown values propagate. Those details are observable JavaScript semantics.

SER only relocates callbacks for Effect operators whose behavior it knows how to preserve. An unknown callback stays opaque, so generator work cannot cross its boundary automatically.