Repository navigation
Errors and Cleanup
Errors can carry typed data. Mark a struct or enum with error, then either
return that value through an error-inclusive return type or throw it.
ErrorValue is the general constraint for marked error types.
error struct MissingShelf { pub shelf: String }
fn locate($name: String): String | MissingShelf
{
if $name == "attic" { return MissingShelf(shelf: $name) }
"ground floor"
}
try
{
let $location: String = locate "attic"
echo $location
}
catch ($problem: MissingShelf)
{
echo "No shelf named" $problem.shelf
}
No shelf named attic
A returned marked error normally propagates when it enters an ordinary result
context. An explicit scalar type that includes the error can capture it for
inspection, but the error remains an obligation to handle or return. Merely
storing it in any or an array is not an acknowledgment.
A matching catch acknowledges the error. throw transfers it again. A function
whose return type admits the error can return it to its caller. Error unions can
provide shared methods while retaining the concrete error's identity.
catch ($stack, $error) receives both context and value. Typed catches select an
error type; a final untyped catch handles anything remaining. RuntimeError
represents interpreter/runtime failures. Parse and compile errors happen before
execution and cannot be caught by the script being compiled.
Runtime traces list the innermost failing call first, then its callers. Frames
include the call's source location; closures appear as <anonymous>. Imported
functions, methods, constructors, accessors, and pipeline callbacks participate.
Native frames are marked [native], with a Rust dispatch boundary separate from
the failure's source location. Earlier successful calls are not part of the trace.
The original failure stays at the top. Parse/compile diagnostics precede runtime
and have no runtime call frames. A two-binding catch exposes a CallStack value
alongside the error; report_error can render that context without executing an
external reporting command.
let $closed = false
try
{
try { throw RuntimeError(what: "example", message: "stop") }
finally { $closed = true }
}
catch ($problem) { echo "handled" }
echo $closed
handled
true
finally runs when its protected block finishes, returns, breaks, continues, or
fails. Keep cleanup focused on local state and resource closing. External
commands, process suspension, and control transfers out of cleanup are rejected;
that includes an external echo. Use report_error $stack $error for native
reporting where appropriate.
If both the body and cleanup fail, the original failure remains primary and the cleanup failure is retained as secondary context. Explicit resource ownership makes cleanup predictable; see Bytes and I/O.
Related: Named unions · Bytes and I/O · HTTP
Begin here
Values and expressions
- Language basics
- Variables and scope
- Numbers and logic
- Strings and paths
- Arrays
- Hash maps
- Ranges and iteration
- Control flow
- Match and type guards
Functions and types
- Functions and calls
- Closures and function types
- Methods and properties
- Structs
- Enums
- Named types and unions
- Conversions
- Types and properties
Shell and modules
- Pipelines
- Pipeline splits
- Pipeline formats
- Commands and exit status
- Redirection
- Environment and exported variables
- Modules and visibility
- Nested modules and directory packages
- Conditional imports and declarations
- Errors and cleanup
- Supervised processes and terminals
Library guides
- Standard library
- The implicit prelude
- Bytes, files, readers, and writers
- Explicit item streams
- JSON documents and typed mapping
- Sockets, DNS, and TLS
- HTTP clients
- HTTP servers
- Framing, server-sent events, and JSON-RPC
- Terminal colors, styles, and geometry
- Build an application console
Interactive use