Skip to Content

Error

error declares error types. Errors are lightweight values: constructed uniformly with new, flowing along the fail channel; once consumed they are ordinary data — printable, reference-comparable, with a readable payload. This page covers the declaration surface of errors; for the complete story of throwing and consuming see Failure.

Declaration Forms

error NotFound(key: string); // shorthand: positional payload error Boom(); // empty payload error Bad(code: int, msg: string); // multiple fields
  • The shorthand form must carry a payload; bare error Name; is illegal.
  • The full body form error Name(key: int) { func Hint() -> string { ... } } can carry methods.
  • The generic error error Bad<T>(value: T); is legal, and each instantiation is its own type (Bad<int> and Bad<string> are different errors); constructor arguments can be inferred (new Bad(42) infers Bad<int>).
  • sealed error Name(...); forbids further inheritance.

Inheritance and the Payload Prefix

Errors inherit singly; the base error follows the colon. The derived payload must have the base payload as a prefix (same order, same names, same types; appending is allowed):

error NotFound(key: string); error Wrapped(key: string, msg: string) : NotFound; val w = new Wrapped("silver", "extra"); print(w.key, w.msg);
silver extra

w carries both of its own fields. A base-error arm catches derived values (write the base error name as a match / recover arm and read the payload at the base-declared prefix positions), and fail contracts override along the inheritance chain.

The errors Union

errors merges several errors into one name, used exclusively in fail clauses:

errors App = NotFound | Boom; func Load(key: string) fail App -> int { if key == "gold" { return 7; } fail new NotFound(key); }

The union appears only in the fail clause position; it is not a value type, and using it as a parameter or variable type reports unknown type.

Construction-Point Origin: @site

Every error value automatically carries the construction point’s file:line:col, read through the hidden field @site:

val b = capture Load("silver"); match b { Success(v) => print("got", v), Failure(e) => print("failed", e.key, e.@site is string), }
failed silver True

@site takes no payload slot and does not participate in equality (error equality is reference comparison).

Discriminating Error Values

Error values support is type tests and as conversions, with inheritance-chain semantics: a derived value is its base error is True, the reverse is False:

func LoadWrap(key: string) fail Wrapped -> int { if key == "gold" { return 7; } fail new Wrapped(key, "extra"); } val e = recover capture LoadWrap("silver") { Success(x) => new NotFound("empty"), Failure(err) => err, }; print(e is NotFound, e is Wrapped); if e is Wrapped { val wr = e as Wrapped; print(wr?.msg); }
True True extra

e holds the derived error Wrapped: e is NotFound is True via the inheritance chain, and e is Wrapped is True by identity. The other way around, a plain NotFound tested with is Wrapped yields False.

Notes

  • For discriminating error kinds, prefer match arms on the error name (which can destructure the payload at the same time); is / as suit lightweight branches. See Failure.
  • Error equality is reference comparison.
Last updated on October 11, 2026