pub enum RuntimeError {
Show 66 variants
Decode(DecodeError),
UnresolvedDefinition(DefinitionId),
NoRootContainer,
StackUnderflow,
CallStackUnderflow,
ContainerStackUnderflow,
InvalidChoiceIndex {
index: usize,
available: usize,
},
NotWaitingForChoice,
StoryEnded,
UnresolvedGlobal(DefinitionId),
TypeError(String),
DivisionByZero,
Unimplemented(String),
UnresolvedExternalCall(DefinitionId),
CaptureUnderflow,
UnknownFlow(String),
FlowAlreadyExists(String),
RanOutOfContent(RanOutOfContentCause),
StepLimitExceeded(u64),
LineLimitExceeded(usize),
LocaleChecksumMismatch {
expected: u32,
actual: u32,
},
LocaleScopeNotInBase(DefinitionId),
LocaleScopeMissing(DefinitionId),
FunctionYielded,
NotEvaluatingFunction,
AlreadyEvaluatingFunction,
FunctionNotFound(String),
AsyncExternalInCall(String),
UnknownPath(String),
JumpWhileAwaitingExternal {
path: String,
external: String,
},
ArgCountMismatch {
target: String,
expected: u8,
got: usize,
},
PrivateAccess {
name: String,
},
IndexOutOfBounds {
index: i32,
len: usize,
},
MapKeyNotFound {
key: String,
},
NotIndexable(&'static str),
InvalidArrayIndex(&'static str),
InvalidMapKeyType(&'static str),
InvalidLiteralIndex(u32),
InvalidNameId(u16),
InvalidShapeId(u32),
NotARecord(&'static str),
RecordFieldNotFound(String),
RecordFieldOffsetOutOfRange {
offset: u16,
len: usize,
},
ConversionParseFailure {
target: &'static str,
input: String,
},
InvalidConversionDomain {
target: &'static str,
got: &'static str,
},
NotCallable(&'static str),
FunctionValueArity {
expected: usize,
got: usize,
bound: usize,
supplied: usize,
},
FunctionValueRehydrationMismatch(String),
FunctionValueCrossFlowLocal(String),
ProjectionInvalidated(String),
CharAtIndexNotInt(&'static str),
CharAtOutOfBounds {
index: i32,
len: usize,
},
StdlibWrongType {
verb: &'static str,
expected: &'static str,
found: &'static str,
},
NotOrderable {
verb: &'static str,
found: &'static str,
},
UnorderedComparand {
verb: &'static str,
},
ComparatorNotAFunction {
verb: &'static str,
found: &'static str,
},
ComparatorReturnType {
verb: &'static str,
found: &'static str,
},
CallbackNotAFunction {
verb: &'static str,
expected: &'static str,
found: &'static str,
},
CallbackReturnType {
verb: &'static str,
expected: &'static str,
found: &'static str,
},
ComparatorEscaped {
verb: &'static str,
role: &'static str,
what: &'static str,
},
ComparatorWroteState {
verb: &'static str,
role: &'static str,
what: &'static str,
},
OptionTruthiness,
AsBindingNotOption {
found: &'static str,
},
EmptyRangeDraw {
range: String,
},
WeightedBadWeight {
found: String,
},
WeightedMalformedTable {
detail: &'static str,
},
}Expand description
The runtime types that appear in bevy-brink’s own public signatures,
re-exported so consumers can name them without depending on brink-runtime:
FlowInstance, Program,
Choice, Step’s
return, RuntimeError’s error,
FallbackHandler for the “no bindings” advance path, the scoped
story-state types a host needs to build a policy and a per-step routing
view (see docs/scoped-flow-state-spec.md): WorldPolicy, Scope,
PolicyError, and ContextView (usually built via
flow_context_view instead of by hand) — and the per-entity durability
types produced/consumed by BrinkGlobals::save_state/load_state and
save_flow_state/load_flow_state (F6.3, see the globals module’s
“Save/load” docs): SaveState and LoadReport.
World is deliberately absent here — it collides with bevy::prelude::World
under a glob import, so it is re-exported under the alias BrinkWorld.
Errors that can occur during story linking or execution.
Variants§
Decode(DecodeError)
UnresolvedDefinition(DefinitionId)
NoRootContainer
StackUnderflow
CallStackUnderflow
ContainerStackUnderflow
InvalidChoiceIndex
NotWaitingForChoice
StoryEnded
UnresolvedGlobal(DefinitionId)
TypeError(String)
DivisionByZero
Unimplemented(String)
UnresolvedExternalCall(DefinitionId)
CaptureUnderflow
UnknownFlow(String)
FlowAlreadyExists(String)
RanOutOfContent(RanOutOfContentCause)
StepLimitExceeded(u64)
LineLimitExceeded(usize)
LocaleChecksumMismatch
LocaleScopeNotInBase(DefinitionId)
LocaleScopeMissing(DefinitionId)
FunctionYielded
NotEvaluatingFunction
AlreadyEvaluatingFunction
FunctionNotFound(String)
call_function was given a name that resolves to no function/knot.
AsyncExternalInCall(String)
A function evaluated via the synchronous call_function path called an
external whose handler deferred (Pending) — it can’t be resolved in a
one-shot synchronous call.
UnknownPath(String)
choose_path_string was given a path that resolves to no knot,
stitch, or label.
JumpWhileAwaitingExternal
choose_path_string was called while the flow is parked on an
unresolved external call. A pending host call cannot be silently
abandoned — resolve it (or reset the story) before jumping.
ArgCountMismatch
A host-directed entry (choose_path_string_with_args) — or a
call_function — was given the wrong number of arguments for the
target’s declared parameters.
Fields
PrivateAccess
A host semantic access (variable get/set, entry lookup, function
eval) targeted a #@private definition while visibility enforcement
was on (M-2b, docs/modules-spec.md §4 boundary rule 2). The host is
outside every module. Dev tooling (play-from-here) opts out via
Story::set_visibility_enforcement.
Persistence (save/load/journal/replay) is unaffected — it never routes
through the enforced surface.
IndexOutOfBounds
Array index read/write out of bounds (0 <= index < len required).
MapKeyNotFound
Map key read (m[k], MapGet) on a key that isn’t present, or a
path-projection write through a ref whose final segment key
isn’t present (docs/t1e-spec.md §4). Indexed assignment
(m[k] = v via the IndexSet opcode) no longer raises this fault on
a missing key — it inserts instead (JS/Python semantics, issue #856,
ruled 2026-07-15).
NotIndexable(&'static str)
a[i]/a[i] = v/m[k]/m[k] = v where a/m isn’t an
Array/Map.
InvalidArrayIndex(&'static str)
Array index expression didn’t evaluate to an Int.
InvalidMapKeyType(&'static str)
Map key expression evaluated to a type outside the ratified key domain (int/string/bool — value-model-spec §4).
InvalidLiteralIndex(u32)
PushLiteral(idx) referenced an index outside the literal pool —
malformed bytecode, not an author-triggerable condition.
InvalidNameId(u16)
A NameId (container/address-path name) referenced an index outside
StoryData::name_table — malformed bytecode, not an
author-triggerable condition. Caught at link time, before any of the
name is used to build path lookup tables.
InvalidShapeId(u32)
RecordNew(shape_id) referenced a shape id outside the compiled
StructShapes table — malformed bytecode.
NotARecord(&'static str)
RecordGetDyn/RecordSetDyn on a value that isn’t a Record.
RecordFieldNotFound(String)
RecordGetDyn/RecordSetDyn named a field the record’s shape
doesn’t declare — a compile-time typo under strict mode (surfaced as
a diagnostic there) or a genuine dynamic mismatch under gradual mode,
both turn-terminating at runtime (spec §11c pattern).
RecordFieldOffsetOutOfRange
RecordGet(offset)/RecordSet(offset) (TM-4c static-offset field
ops) with an offset outside the popped record’s own field vector.
These ops never re-check the record’s shape (that’s the payoff over
RecordGetDyn/RecordSetDyn) — only the field count is verified, so
this is the sole fault this pair can produce, malformed bytecode or
otherwise.
ConversionParseFailure
int(x)/float(x) where x is a String that fails to parse as
the target numeric type. Turn-terminating fault — no
zero-defaulting, no silent garbage (ruling 1: “Parse failure is a
turn-terminating fault… like a missing map key”). Unlike this,
the classic uppercase INT()/FLOAT() builtins keep their
pre-existing silent-0-on-string-parse-failure legacy behavior
(value_ops::cast_to_int/cast_to_float) untouched within their own
Int/Float/Bool/String domain — oracle-byte-identical, a
distinct code path. Outside that domain (divert targets, pointers,
collections, records, function/handle/projection values), the
uppercase builtins now raise InvalidConversionDomain
too (issue #955) instead of the wildcard-fold-to-zero they used to —
those variants were never oracle-reachable through INT()/FLOAT().
InvalidConversionDomain
int(x)/float(x) where x is outside the permissive
numeric+bool domain (divert targets, LIST values, arrays, maps,
records) — compile error under types = strict (brink-analyzer’s
intrinsic typing/domain check), turn-terminating fault under
types = gradual (ruling 2). Also raised by the classic uppercase
INT()/FLOAT() builtins (value_ops::cast_to_int/cast_to_float)
for the same reason, with an uppercase target label (issue #955) —
no spec (value-model-spec.md, t1c/t1d/t1e-spec.md) rules a
conversion for those variants, so faulting is the conservative
default rather than the old silent zero.
NotCallable(&'static str)
call(f, …) / a direct f(…) where the callee value is not a
function value (nor a divert target). Gradual-mode dispatch fault —
“no silent garbage” (spec §3, value-model-spec §11c).
FunctionValueArity
Calling a function value with the wrong number of arguments: the bound prefix plus the supplied args must exactly equal the target’s declared arity (spec §3). Turn-terminating in gradual mode; strict mode catches it at compile time (spec §4).
FunctionValueRehydrationMismatch(String)
A rehydrated function value’s bound env no longer matches the current signature — a param was renamed, reordered, or re-moded across a recompile (spec §6). A defined fault, never a silent misbinding.
FunctionValueCrossFlowLocal(String)
Invoking a function value that ref-binds a flow-private (#@local)
cell (spec §3). T1c ships this fault instead of creating-flow identity
(#597): a #@local-ref binding can only be dereferenced safely from
its creating flow, and no creating-flow identity is tracked yet, so the
invocation faults rather than risk a silent cross-flow misbinding. The
payload is the bound cell’s name.
ProjectionInvalidated(String)
A live path projection’s snapshot segments no longer resolve against
the root cell’s current value at read or write time: a shrunk
array, a removed map key, or a struct field dropped by recompile.
The single ratified turn-terminating fault for every path-invalidation
cause (spec §1(2): “a defined turn-terminating runtime fault — not a
clamp, not UB”). The payload carries the underlying cause (an
IndexOutOfBounds/MapKeyNotFound/RecordFieldNotFound-shaped
message, or a root-resolution failure).
CharAtIndexNotInt(&'static str)
char_at(s, i)’s index expression didn’t evaluate to an Int.
CharAtOutOfBounds
char_at(s, i) where i is outside [0, char_count) — chars
(Unicode scalar values), not UTF-8 bytes (the issue’s “author
sanity” ruling), so len is s.chars().count(), never
s.len(). Turn-terminating fault, no silent empty/clamped result
(value-model-spec §11c) — matches IndexOutOfBounds’s posture for
arrays.
StdlibWrongType
A stdlib verb was handed a container/argument of the wrong runtime
type — find on a non-string, min/first/pop on a non-array,
get/contains_value/clear on a non-map. A malformed question
is a bug (the ruled fault-vs-absence doctrine), so this is a
turn-terminating fault, never a none.
NotOrderable
min/max reached an element outside the currently-orderable set
(int/float/bool/string, homogeneous per the §4b roster), or a
cross-type pair (int vs string). Turn-terminating fault — an
unorderable extremum question is malformed, not absent.
UnorderedComparand
DEV mode only: an ordering verb (sort/sorted/min/max; A7
adds heap_push) reached a float NaN comparand. NaN flows freely
through arithmetic — ordering contexts are where it stops: in dev
mode the upstream bug surfaces at its first ordering consumption as
this turn-terminating fault. PROD mode instead places NaN by the
pinned non-fabricating total order (-0 == +0 ties, NaN greatest,
NaN-vs-NaN ties) and keeps moving — the mode changes WHERE execution
stops, never WHAT values are fabricated. sort_by/sorted_by
deliberately do NOT raise this (F14: the comparator owns the order).
ComparatorNotAFunction
sort_by/sorted_by was handed a comparator that is not a function
value (FnRef/Closure). Malformed question — turn-terminating.
ComparatorReturnType
A sort_by/sorted_by comparator returned something other than an
int (F0’s ruled shape: negative = less, zero = tie, positive =
greater). Turn-terminating — a silent coercion here would scramble
the order.
CallbackNotAFunction
A fn-value verb (map/filter/fold/filter_map/each/
map_each — docs/stdlib-spec.md §4, issue #1679) was handed a
callback that is not a function value (FnRef/Closure). Malformed
question — turn-terminating, pure or effectful alike. Distinct from
ComparatorNotAFunction because each
verb names its own expected shape.
Fields
CallbackReturnType
A fn-value verb’s callback returned a value of the wrong shape —
filter, whose predicate must return a bool, and filter_map,
whose Option-mapper must return an Option. Coercing truthiness or
unwrapping a non-Option here would silently change which elements
survive, so this is turn-terminating.
ComparatorEscaped
A sort_by/sorted_by comparator, or a fn-value verb’s callback
(issue #1679, pure quartet and effectful pair alike), broke a
contract the VM can observe: it presented a choice, reached
-> DONE/-> END, called an external function, exceeded the
nested-evaluation step budget, or recursed past the nesting depth
limit. These four are architectural — no handler exists mid-opcode —
so they fire for each/map_each exactly as for the pure quartet;
being effectful widens what a callback may do, not what the VM can
honor mid-op. The checker enforces the pure·silent half of the
contract statically where the callee’s origin is provable (E119,
pure quartet only); this fault is the gradual-mode runtime residual
either way. role names the shape the author wrote —
"comparator" for sort_by/sorted_by, "callback" for every
fn-value verb (callback_role) — so a map/each/… author is
never told they wrote a bad comparator.
ComparatorWroteState
DEV mode only (F34, ruled 2026-07-19): a sort_by/sorted_by
comparator, or a pure fn-value verb’s callback
(map/filter/fold/filter_map, issue #1679), performed a
world-write mid-evaluation — assigned a global (directly, or through
a ref-parameter pointer / path projection) or advanced the RNG
cell (a draw IS a write: a random comparator/callback is exactly the
non-determinism the pure·silent contract bans). PROD mode skips the
check entirely and the write executes — defined and deterministic,
because the stable merge-sort’s comparison sequence is fixed and the
fn-value verbs walk their array in iteration order (the mode changes
WHERE execution stops, never WHAT is produced). Visit-count
increments from the callee’s own invocation are NOT world-writes —
they are the ruled in-story dispatch semantics and stay exempt.
Reads are not guarded at runtime (E119’s static bound owns the read
posture, where E119 gates at all). role is the same author-facing
noun as ComparatorEscaped; like it,
this is the gradual-mode runtime residual of the E119 gate. Never
fires for the effectful pair (each/map_each, issue #1679 slice
2, in either mode): world-writes are exactly what they exist to
permit — see vm::guard_comparator_write.
OptionTruthiness
A Value::OptionVal reached the VM’s truthiness evaluation (GotoIf,
JumpIfFalse, Not, a choice condition). Option has no
truthiness — truthiness is a quiet coercion of exactly the kind
Option[T] ≠ T exists to ban — so this is the gradual-mode
turn-terminating fault; types = strict reports the same condition
statically (E116). Authors write == none / == some(x), or the
as-binding (B1b, issue #1475 — see Self::AsBindingNotOption,
its own fault). Supersedes NS-A1’s shipped falsy-none behavior.
AsBindingNotOption
Opcode::OptionBind received a non-Option operand — if EXPR as name { … } where EXPR does not evaluate to an Option[T]. The
binding’s whole job is to unwrap Option[T] to T, so there is
nothing to bind. This is the gradual-mode residual of the checker’s
strict-mode E147 (the same statically/dynamically paired posture
Self::OptionTruthiness has with E116); on the native surface,
which is strict-only, E147 catches every statically classifiable
case first and this fault is the backstop for the rest.
EmptyRangeDraw
int(range) reached an empty range at runtime — the F8 gradual-
mode residual, and THE template for every future value refinement:
under gradual typing the refinement check is inert at compile time
and this turn-terminating fault is what remains; under types = strict the same condition is unrepresentable (the checker demands
NonEmptyRange evidence — a provably-inhabited literal or a
non_empty(r) unwrap — and reports E117 statically). A draw from
nothing is a malformed question, never an absence, so this is a
fault and not a none (the ruled fault-vs-absence doctrine;
contrast pick(0..0), which IS absence and returns none).
WeightedBadWeight
weighted(…) reached a computed weight that is not a positive
int at construction time — the E078-style split’s runtime half: a
weight the checker could classify statically is the E120 compile
error; a computed weight that turns out zero/negative/non-int is
this turn-terminating construction fault. Construction is the
validator (the §7 parse-don’t-validate shape), so roll over any
table that exists is total.
Fields
WeightedMalformedTable
The weighted_new op received a malformed pair row (empty, or an
odd flattened length). Unreachable through the compiler — the E120
gate refuses empty/odd construction shapes statically — so this
guards hand-crafted or corrupt bytecode only (the malformed-bytecode
robustness discipline, never a panic).
Trait Implementations§
Source§impl Clone for RuntimeError
impl Clone for RuntimeError
Source§fn clone(&self) -> RuntimeError
fn clone(&self) -> RuntimeError
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for RuntimeError
impl Debug for RuntimeError
Source§impl Display for RuntimeError
impl Display for RuntimeError
Source§impl Error for RuntimeError
impl Error for RuntimeError
Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()
Source§impl From<DecodeError> for RuntimeError
impl From<DecodeError> for RuntimeError
Source§fn from(source: DecodeError) -> RuntimeError
fn from(source: DecodeError) -> RuntimeError
Source§impl From<RuntimeError> for InkbLoaderError
impl From<RuntimeError> for InkbLoaderError
Source§fn from(source: RuntimeError) -> Self
fn from(source: RuntimeError) -> Self
Source§impl From<RuntimeError> for BrinkCallError
impl From<RuntimeError> for BrinkCallError
Source§fn from(source: RuntimeError) -> Self
fn from(source: RuntimeError) -> Self
Source§impl From<RuntimeError> for InkLoaderError
impl From<RuntimeError> for InkLoaderError
Source§fn from(source: RuntimeError) -> Self
fn from(source: RuntimeError) -> Self
Source§impl From<RuntimeError> for CompileStoryInlineError
impl From<RuntimeError> for CompileStoryInlineError
Source§fn from(source: RuntimeError) -> Self
fn from(source: RuntimeError) -> Self
Source§impl PartialEq for RuntimeError
impl PartialEq for RuntimeError
impl StructuralPartialEq for RuntimeError
Auto Trait Implementations§
impl Freeze for RuntimeError
impl RefUnwindSafe for RuntimeError
impl Send for RuntimeError
impl Sync for RuntimeError
impl Unpin for RuntimeError
impl UnsafeUnpin for RuntimeError
impl UnwindSafe for RuntimeError
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> ConditionalSend for Twhere
T: Send,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.