Custom Errors
Named error declarations describe typed failure ABIs. On EVM they lower to
Solidity custom errors and are the preferred way to fail a route, a where
guard, or a from check.
Declaration
Errors may appear at program scope or entity scope:
error InsufficientBalance(have: U256, need: U256);
entity Vault {
error Unauthorized();
routes {
withdraw(amount: U256)
from Owner(m_owner) : throw Unauthorized()
where m_balance >= amount : throw InsufficientBalance(m_balance, amount)
=> [
~> msg::sender with { value: amount }
]
kill()
from Owner(m_owner) : throw Unauthorized()
=> [
throw Unauthorized()
]
}
}
Raising errors
| Form | Where |
|---|---|
: throw ErrorName(args) | After a where condition or a from clause |
throw ErrorName(args) | As a terminator action in a route body |
throw / throw Name(...) is a terminator: later actions in the same
route (or phase) do not run.
Validation
| Rule | Code |
|---|---|
| Error must be declared at program or entity scope | V38 |
| Argument arity / types must match | V39 |
EVM lowering
| Cambrian | Solidity |
|---|---|
error Name(...); | error Name(...); |
throw Name(args) / : throw Name(args) | revert Name(args); |
Named vs numeric throw
Older sources may still use a numeric form (: throw 100). Prefer named
errors for new code on EVM: they produce typed custom errors that tools and
callers can decode. Numeric throw N remains accepted for compatibility and
lowers to a string-style revert, but it is not the preferred EVM story.