On this page

PreprocessError

Trace SER's transform base error and its direct class-member trigger.

What this error means and what can trigger it

PreprocessError is the common base for synchronous failures raised while SER lowers component script or markup. It extends RuntimeError with a filename, which lets Vite and other tooling retain source context without having to parse the diagnostic text.

Most failures use a concrete subclass. The base class itself has one production trigger, albeit an unusual one: a class field initializer contains a top-level yield*. For example, class Store { value = yield* LoadValue() } places effect work inside object construction rather than component-level script work.

The detector stops at nested function boundaries. A yield* inside an arrow, method, accessor, or other nested function is not treated as top-level work belonging to the field initializer.

Exactly where it triggers

const bad_member = find_class_member_with_yield_star(stmt);

if (!bad_member) {
	return;
}

throw new PreprocessError(
	[
		`[ASYNC_EFFECT_IN_CLASS_MEMBER]: ${filename}: yield* cannot be used inside class members.`,
		`Class fields and methods are not component top-level reactive work. Move the Effect work into a script effect statement before assigning it to the class instance.`,
		"",
		"Problematic member:",
		slice(content, bad_member),
	].join("\n"),
	filename,
);

The compiler raises this synchronously during the Vite/SER transform, before the component module can evaluate and before any effect runtime exists.

For reference, the base class is declared at modules/svelte-effect-runtime/src/errors.ts L55 @ C14.

Why this is the case

SER lowers component-level statements into dispatcher-owned work. A class field follows JavaScript object-construction timing and may run once per instance, long after or long before the component-level statement SER would have generated. Hoisting the expression would change evaluation order and ownership; leaving it in place would put generator syntax into a synchronous initializer.

The compiler rejects the field instead of guessing whether the result should belong to the component, the class instance, or every future instance.