Skip to content
Noodle
InstallLearnPlayground
GitHub

Error handling

Use typed errors for expected failures that callers may propagate, inspect, or recover from. Errors are values in a declared set; they are separate from host exceptions and unrecoverable runtime traps.

An errortype is non-generic and uses datatype-like constructors:

errortype LookupError
MissingValue
InvalidKey(String)
end

Constructors belong to their declaring error type, such as LookupError::InvalidKey("name").

errortype LookupError
MissingValue
InvalidKey(String)
end
func require_value(option : Option[Int]) throws LookupError -> Int do
switch option
case Option::Some(value) then value
case Option::None then throw LookupError::MissingValue
end
end

Inside the body, the successful result is still Int. To callers, the function returns the standard library’s canonical Result[Int, LookupError]: normal completion becomes Result::Ok, while throw exits with Result::Err.

errortype LookupError
MissingValue
InvalidKey(String)
end
func require_value(option : Option[Int]) throws LookupError -> Int do
switch option
case Option::Some(value) then value
case Option::None then throw LookupError::MissingValue
end
end
func double_value(option : Option[Int]) throws LookupError -> Int do
require_value(option)! * 2
end

For Result[T, E], postfix ! extracts T from Ok. An Err returns early from the directly enclosing function. That function must declare a compatible error set.

The operand is evaluated once. Propagation does not catch host exceptions or convert unrelated error values.

errortype LookupError
MissingValue
InvalidKey(String)
end
func require_value(option : Option[Int]) throws LookupError -> Int do
switch option
case Option::Some(value) then value
case Option::None then throw LookupError::MissingValue
end
end
func double_value(option : Option[Int]) throws LookupError -> Int do
require_value(option)! * 2
end
func main() -> Unit do
result = double_value(Option::None);
switch result
case Result::Ok(value) then Debug.trace(value)
case Result::Err(LookupError::MissingValue) then
Console.println("No value was provided")
case Result::Err(LookupError::InvalidKey(key)) then
Console.println("Invalid key: " ++ key)
end;
end

Handle the result at the layer that owns recovery or presentation. Use ! when the current function should preserve the same failure contract.

An error type may include all constructors of one or more base error types:

errortype StorageError
Unavailable
end
errortype ServiceError extends StorageError
InvalidRequest
end

A StorageError value widens to ServiceError without a wrapper. Inherited constructors remain qualified by their declaring owner, so code constructs and matches StorageError::Unavailable, not ServiceError::Unavailable.

A test declaration has no explicit throws clause. The compiler collects errors propagated or thrown directly by the test body and builds a private test-only envelope. That is why both application errors and Testing.assert_equal(...)! can leave a test naturally.

Option and Result are standard-library types; their constructors and operators are covered in Option and Result.

Next: Asynchronous code.