scrml.dev v0.7.1
Reference › Errors

E-MATCH-ONTRANSITION-FORBIDDEN

<onTransition> element used inside a <match> block. Transition handlers are engine-only.

Error Compile-time SPEC §18.0.2 (normative)

What it means

Block-form <match> is rules-inert — case analysis on a value, NOT a state machine. Transitions don't occur in match (the matched-on value either is or isn't a given variant; nothing transitions). So <onTransition> handlers are structurally meaningless here. The compiler forbids them — not as a lint, but as an error — because their presence indicates the wrong primitive.

Minimal reproducer

type Phase:enum = { Idle, Loading, Done }

<match for=Phase>
  <Idle></>
  <Loading></>
  <Done></>

  <onTransition to=.Done>
    // ^^^^^^^^^^^^^^^^^^^^^^
    // E-MATCH-ONTRANSITION-FORBIDDEN: transition handlers are engine-only.
    ${ analytics.track("done") }
  </onTransition>
</match>

How to fix

Promote the <match> to <engine>. Same exhaustive case-analysis shape; adds active rules + the ability to declare transition handlers. State-children carry forward verbatim — the wrapper swap is the commitment moment. The compiler emits I-MATCH-PROMOTABLE on the original site when transition-shape intent is detected.

<engine for=Phase initial=.Idle>
  <Idle    rule=.Loading />
  <Loading rule=.Done    />
  <Done    rule=.Idle    />

  <onTransition to=.Done>
    ${ analytics.track("done") }
  </onTransition>
</engine>

Why match is rules-inert

Match is one of two Tier-1 shapes (the other being JS-style match expr { } value-return form). Both are case analysis on a discriminating type with compile-time exhaustiveness. NEITHER models transitions — match looks at WHAT a value IS, not how it moves between states. The engine wrapper adds:

  • Active rule= contract per state-child (single-target, multi-target, or wildcard).
  • <onTransition> handlers filterable by from / to / once / if.
  • effect= attribute for per-rule inline effects.
  • <onTimeout> per-state timers and <onIdle> engine-wide watchdog.

Related

  • <match> — rules-inert Tier 1; the locus where this error fires.
  • <engine> — Tier 2 promotion target; full transition surface.
  • <onTransition> — element reference. Legal only inside <engine>.
  • E-MATCH-EFFECT-FORBIDDEN — companion error for effect= attribute (also engine-only).
  • W-MATCH-RULE-INERT — rule= warning (legal but inert; promote to engine to activate).

Specification

Normative text: SPEC §18.0.2 (match attribute legality: rule= inert / effect= forbidden / onTransition forbidden), §51.0.H (<onTransition> in engine context), §34 catalog row. Spec lives at compiler/SPEC.md .