Module error
Standard error handling types and traits for Yo.
Stability
unstable — the Error trait, AnyError, Exception and the IoExn
bundle are the core of every fallible API in std and their shapes are
settled. The one thing that blocked freezing them was a COMPILER defect,
not a design gap: source()'s Option(Dyn(SelfTrait)) result had lost the
Error trait on an erased receiver, so a caller could follow one link and
print it but could not store, re-erase, downcast or re-throw it — and
ErrorChain/root_cause are exactly that store.
That defect is FIXED (2026-09-14, TraitT identity is the trait's id
rather than its externally-attached name —
issues/fixed/self-trait-in-a-return-type-loses-the-trait-on-an-erased-receiver.md,
filed as #521). The walk type-checks and runs; it is gated by
tests/error_source_chain.test.yo.
ErrorChain/root_cause were then held one more release by the usual
two-release sequencing — std/ is compiled by the SEED during bootstrap, so
std code performing the walk could not build until a seed carried the fix.
v0.2.34 is that seed, and both landed: root_cause(err) for the
innermost error and error_chain(err) for the whole walk as an Iterator.
Nothing in this module is waiting on a compiler defect or a decision.
Types
Type-erased dynamic error type. Wraps any type implementing Error.
An error that adds a message to the one underneath it — Rust's
anyhow::Context / .context(...).
This is the type that makes Error.source worth having: nothing else in
the tree overrides it, so before this every error chain was one link long.
to_string renders the whole chain, innermost last:
e := Context.new(`while loading the config`, dyn(io_err));
println(e.to_string()); // while loading the config: no such file
Fields
| Name | Type | Description |
|---|---|---|
message | String | What was being attempted. |
cause | dyn(ToString + Error) | The error that caused it. |
Trait Implementations
impl(Context, ...)
impl(Context, ToString(...))
to_string : (Context) fn(inout(self) : Context) -> Stringimpl(Context, Error(...))
source : (Context) fn(inout(self) : Context) -> Option(dyn(ToString + ))The error that caused this one, or .None at the root of the chain.
Rust's Error::source. Defaulted to .None, so an error with nothing
underneath it implements the trait by saying only what it is; a wrapper
overrides it to hand back what it wrapped. Walking the chain to the root
cause works as of 2026-09-14 — the returned Dyn used to lose the
Error trait on an erased receiver, so a caller could print one link but
not follow it (#521,
issues/fixed/self-trait-in-a-return-type-loses-the-trait-on-an-erased-receiver.md).
Parameters
| Name | Type | Notes |
|---|---|---|
self | Context |
Non-resumable exception handling effect record.
Use throw to raise an AnyError and abort the current computation.
throw is ctl(...) — handler body may contain unwind, and the
handler value is frame-bound (see plans/archive/EXPLICIT_EFFECTS.md §4).
Fields
| Name | Type | Description |
|---|---|---|
throw | ctl(generic(ResumeType) error : dyn(ToString + Error)) -> ResumeType |
Creates a resumable exception effect record parameterized by the resume type.
Unlike Exception, the handler can return a value to resume the computation.
throw is still ctl(...) because the handler MAY choose to unwind;
regular fn returns are also valid via subtyping fn <: ctl.
Type Parameters
| Name | Type | Notes |
|---|---|---|
ResumeType | Type | comptime |
An iterator over an error and everything underneath it — Rust's
anyhow::Error::chain / std::error::Report's walk.
The first next() yields the error the chain was built from, then each
source() in turn, ending when one reports .None. So a chain always has
at least one link.
{ error_chain } :: import("std/error");
(e : AnyError) = dyn(Context.new(`while loading config`, io_err));
(n : usize) = usize(0);
it := error_chain(e);
(going : bool) = true;
while(runtime(going), {
match(it.next(), .Some(link) => { n = (n + usize(1)); }, .None => { going = false; });
});
The cursor is spelled with match rather than Option's inherent methods
throughout: Option(Dyn(Trait)) cannot take one — the specialization is
called but never emitted, so the C fails to compile
(issues/fixed/option-of-a-trait-object-never-emits-its-inherent-methods.md).
Fields
| Name | Type | Description |
|---|---|---|
_cur | Option(dyn(ToString + )) |
Trait Implementations
impl(generic(I : Type), where(I <: Iterator), I : (Iterator))
impl(generic(I : Type), where(I <: Iterator), I : (Iterator))
map : fn(generic(A, B, F) self : I : (Iterator), f : F : (Fn(A) -> B)) -> IterMap(I : (Iterator), B, F : (Fn(A) -> B))filter : fn(generic(A, F) self : I : (Iterator), f : F : (Fn(A) -> bool)) -> IterFilter(I : (Iterator), F : (Fn(A) -> bool))Parameters
| Name | Type | Notes |
|---|---|---|
self | I : (Iterator) | |
f | F : (Fn(A) -> bool) |
Returns: IterFilter(I : (Iterator), F : (Fn(A) -> bool))
take : fn(generic(A) self : I : (Iterator), n : usize) -> IterTake(I : (Iterator))skip : fn(generic(A) self : I : (Iterator), n : usize) -> IterSkip(I : (Iterator))enumerate : fn(generic(A) self : I : (Iterator)) -> IterEnumerate(I : (Iterator))zip : fn(generic(A, J, B) self : I : (Iterator), other : J : (Iterator)) -> IterZip(I : (Iterator), J : (Iterator))fold : fn(generic(A, Acc, F) self : I : (Iterator), init : Acc, f : F : (Fn(Acc, A) -> Acc)) -> Accfor_each : fn(generic(A, F) self : I : (Iterator), f : F : (Fn(A) -> unit)) -> unitcount : fn(generic(A) self : I : (Iterator)) -> usizeany : fn(generic(A, F) self : I : (Iterator), pred : F : (Fn(A) -> bool)) -> boolall : fn(generic(A, F) self : I : (Iterator), pred : F : (Fn(A) -> bool)) -> boolfind : fn(generic(A, F) self : I : (Iterator), pred : F : (Fn(A) -> bool)) -> Option(A)position : fn(generic(A, F) self : I : (Iterator), pred : F : (Fn(A) -> bool)) -> Option(usize)last : fn(generic(A) self : I : (Iterator)) -> Option(A)nth : fn(generic(A) self : I : (Iterator), n : usize) -> Option(A)sum : fn(generic(A) self : I : (Iterator)) -> A : ((Output : Type, + : fn(lhs : Self, rhs : A) -> Output) + Default)min : fn(generic(A) self : I : (Iterator)) -> Option(A : ((< : fn(lhs : Self : ((== : fn(lhs : Self, rhs : A) -> bool, != : fn(lhs : Self, rhs : A) -> bool)), rhs : A) -> bool, <= : fn(lhs : Self, rhs : A) -> bool, > : fn(lhs : Self, rhs : A) -> bool, >= : fn(lhs : Self, rhs : A) -> bool, cmp : fn(lhs : Self, rhs : A) -> Ordering)))Parameters
| Name | Type | Notes |
|---|---|---|
self | I : (Iterator) |
Returns: Option(A : ((< : fn(lhs : Self : ((== : fn(lhs : Self, rhs : A) -> bool, != : fn(lhs : Self, rhs : A) -> bool)), rhs : A) -> bool, <= : fn(lhs : Self, rhs : A) -> bool, > : fn(lhs : Self, rhs : A) -> bool, >= : fn(lhs : Self, rhs : A) -> bool, cmp : fn(lhs : Self, rhs : A) -> Ordering)))
max : fn(generic(A) self : I : (Iterator)) -> Option(A : ((< : fn(lhs : Self : ((== : fn(lhs : Self, rhs : A) -> bool, != : fn(lhs : Self, rhs : A) -> bool)), rhs : A) -> bool, <= : fn(lhs : Self, rhs : A) -> bool, > : fn(lhs : Self, rhs : A) -> bool, >= : fn(lhs : Self, rhs : A) -> bool, cmp : fn(lhs : Self, rhs : A) -> Ordering)))Parameters
| Name | Type | Notes |
|---|---|---|
self | I : (Iterator) |
Returns: Option(A : ((< : fn(lhs : Self : ((== : fn(lhs : Self, rhs : A) -> bool, != : fn(lhs : Self, rhs : A) -> bool)), rhs : A) -> bool, <= : fn(lhs : Self, rhs : A) -> bool, > : fn(lhs : Self, rhs : A) -> bool, >= : fn(lhs : Self, rhs : A) -> bool, cmp : fn(lhs : Self, rhs : A) -> Ordering)))
chain : fn(generic(A, J) self : I : (Iterator), other : J : (Iterator)) -> IterChain(I : (Iterator), J : (Iterator))take_while : fn(generic(A, F) self : I : (Iterator), f : F : (Fn(A) -> bool)) -> IterTakeWhile(I : (Iterator), F : (Fn(A) -> bool))Parameters
| Name | Type | Notes |
|---|---|---|
self | I : (Iterator) | |
f | F : (Fn(A) -> bool) |
Returns: IterTakeWhile(I : (Iterator), F : (Fn(A) -> bool))
skip_while : fn(generic(A, F) self : I : (Iterator), f : F : (Fn(A) -> bool)) -> IterSkipWhile(I : (Iterator), F : (Fn(A) -> bool))Parameters
| Name | Type | Notes |
|---|---|---|
self | I : (Iterator) | |
f | F : (Fn(A) -> bool) |
Returns: IterSkipWhile(I : (Iterator), F : (Fn(A) -> bool))
filter_map : fn(generic(A, B, F) self : I : (Iterator), f : F : (Fn(A) -> Option(B))) -> IterFilterMap(I : (Iterator), B, F : (Fn(A) -> Option(B)))Parameters
| Name | Type | Notes |
|---|---|---|
self | I : (Iterator) | |
f | F : (Fn(A) -> Option(B)) |
Returns: IterFilterMap(I : (Iterator), B, F : (Fn(A) -> Option(B)))
peekable : fn(generic(A) self : I : (Iterator)) -> IterPeekable(I : (Iterator), A)collect : fn(self : I : (Iterator), C : Type) -> C : (FromIterator)impl(ErrorChain, Iterator(...))
Item : AnyErrornext : (ErrorChain) fn(inout(self) : ErrorChain) -> Option(dyn(ToString + ))Advance the iterator and return the next value, or None when exhausted.
Parameters
| Name | Type | Notes |
|---|---|---|
self | ErrorChain |
Traits / Modules
Standard error trait for typed error propagation.
All error types should implement this trait along with ToString.
Methods
source : fn(inout(self) : Self : (ToString)) -> Option(dyn(ToString + ))The error that caused this one, or .None at the root of the chain.
Rust's Error::source. Defaulted to .None, so an error with nothing
underneath it implements the trait by saying only what it is; a wrapper
overrides it to hand back what it wrapped. Walking the chain to the root
cause works as of 2026-09-14 — the returned Dyn used to lose the
Error trait on an erased receiver, so a caller could print one link but
not follow it (#521,
issues/fixed/self-trait-in-a-return-type-loses-the-trait-on-an-erased-receiver.md).
Parameters
| Name | Type | Notes |
|---|---|---|
self | Self : (ToString) |
Implementors
Functions
Common effect bundle: Io + Exception.
Used as the effect parameter for Futures that perform Io and may throw.
Construct with { io, exn }; project with e.io or e.exn.
The innermost error in a chain — Rust's anyhow::Error::root_cause.
Follows source() until an error reports none, and returns that one. An
error with nothing underneath it is its own root cause, so this never
returns .None and callers need no unwrapping.
{ root_cause } :: import("std/error");
e := dyn(Context.new(`while loading the config`, dyn(io_err)));
println(root_cause(e).to_string()); // the io error, not the context
Spelled with match rather than Option methods deliberately: the result
of source() is an Option(Dyn(Error)), and an Option of a trait object
cannot take an inherent Option method — the specialization is called but
never emitted, so the C fails to compile
(issues/fixed/option-of-a-trait-object-never-emits-its-inherent-methods.md). That
is a separate open defect; this walk stays clear of it.
Parameters
| Name | Type | Notes |
|---|---|---|
err | AnyError |
Returns: AnyError
Start a chain at err. The first next() returns err itself.
Parameters
| Name | Type | Notes |
|---|---|---|
err | AnyError |
Returns: ErrorChain