Skip to main content

RuntimeError

Enum RuntimeError 

Source
pub enum RuntimeError {
Show 67 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, }, DebugBudgetExceeded { breakpoint: String, ceiling: u64, },
}
Expand description

Errors that can occur during story linking or execution.

Variants§

§

Decode(DecodeError)

§

UnresolvedDefinition(DefinitionId)

§

NoRootContainer

§

StackUnderflow

§

CallStackUnderflow

§

ContainerStackUnderflow

§

InvalidChoiceIndex

Fields

§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

Fields

§expected: u32
§actual: u32
§

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.

Fields

§path: String
§external: String
§

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

§target: String

The knot/stitch/function path or name.

§expected: u8

Declared parameter count.

§got: usize

Arguments the host supplied.

§

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.

Fields

§name: String

The private definition’s name or path, as the host supplied it.

§

IndexOutOfBounds

Array index read/write out of bounds (0 <= index < len required).

Fields

§index: i32
§len: usize
§

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).

Fields

§

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.

Fields

§offset: u16
§len: usize
§

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().

Fields

§target: &'static str
§input: String
§

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.

Fields

§target: &'static str
§got: &'static str
§

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).

Fields

§expected: usize
§got: usize
§bound: usize
§supplied: usize
§

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.

Fields

§index: i32
§len: usize
§

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.

Fields

§verb: &'static str
§expected: &'static str
§found: &'static str
§

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.

Fields

§verb: &'static str
§found: &'static str
§

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).

Fields

§verb: &'static str
§

ComparatorNotAFunction

sort_by/sorted_by was handed a comparator that is not a function value (FnRef/Closure). Malformed question — turn-terminating.

Fields

§verb: &'static str
§found: &'static str
§

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.

Fields

§verb: &'static str
§found: &'static str
§

CallbackNotAFunction

A fn-value verb (map/filter/fold/filter_map/each/ map_eachdocs/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

§verb: &'static str
§expected: &'static str

The callback’s declared shape, already back-quoted for the message (e.g. `fn(T): bool`).

§found: &'static str
§

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.

Fields

§verb: &'static str
§expected: &'static str
§found: &'static str
§

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.

Fields

§verb: &'static str
§role: &'static str
§what: &'static str
§

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.

Fields

§verb: &'static str
§role: &'static str
§what: &'static str
§

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.

Fields

§found: &'static str

The offending operand’s runtime type name (vm::value_type_name).

§

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).

Fields

§range: String

The written form of the offending range (0..0, 5..=2, …).

§

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

§found: String

Display form of the offending weight value (0, -3, 1.5, a type name for non-numerics).

§

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).

Fields

§detail: &'static str
§

DebugBudgetExceeded

A Story::debug_run/debug_step call exceeded its own debug-only step budget (debug_control::DEFAULT_DEBUG_BUDGET unless the caller overrides the ceiling) before reaching a breakpoint, watchpoint, or step target. Distinct from StepLimitExceeded on purpose — that variant reports the production step-limit firing; this one reports the separate debug-stepping budget firing (2026-08-28 step-limit ruling on issue #3186: “Exceeding the debug budget MUST be its own distinct reportable outcome, never StepLimitExceeded, which would be a lie about what happened”). breakpoint names what the debugger was doing when the budget ran out (a breakpoint/watchpoint name, or "step"/"run" for an unconditional step/run) so the studio can report “breakpoint condition ran too long” and name it, per the ruling’s own framing.

Fields

§breakpoint: String

Name of the breakpoint/watchpoint/step operation in progress when the budget was exhausted.

§ceiling: u64

The debug budget’s ceiling (not the production step limit).

Trait Implementations§

Source§

impl Clone for RuntimeError

Source§

fn clone(&self) -> RuntimeError

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for RuntimeError

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Display for RuntimeError

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Error for RuntimeError

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0:

use the Display impl or to_string()

1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more
Source§

impl From<DecodeError> for RuntimeError

Source§

fn from(source: DecodeError) -> Self

Converts to this type from the input type.
Source§

impl From<RuntimeError> for SessionError

Source§

fn from(source: RuntimeError) -> Self

Converts to this type from the input type.
Source§

impl PartialEq for RuntimeError

Source§

fn eq(&self, other: &RuntimeError) -> bool

Equality operator ==. Read more
1.0.0 (const: unstable) · Source§

fn ne(&self, other: &Rhs) -> bool

Inequality operator !=. Read more
Source§

impl StructuralPartialEq for RuntimeError

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.