Return custom errors#

This guide shows how to return custom errors from your Rust smart contract.

Defining and deriving#

Custom error codes help communicate why a contract rejects and can be returned both during initialization and during updates.

On-chain, smart contracts return a numeric error code and an optional serialized return value when rejecting. This is also the case when using a custom error type. Therefore, a mapping from the custom error type to Reject, in the form of an implementation of From<MyError> for Reject, is needed. You can derive the implementation automatically with #[derive(Reject)] if the type also implements Serial (also derivable). The Serial instance is needed because the whole data type is serialized and included as the optional return value. Here is a typical example:

#[derive(Serial, Reject)]
enum MyError {
    ErrOne,
    ErrTwo,
}

Note

The valid range of error codes is i32::MIN..-1. When deriving Reject, each variant is assigned an error code as determined by the ordering. First variant (ErrOne in example) gets -1, second variant (ErrTwo in example) gets -2, and so on.

Warning

Deriving Reject for enums with custom discriminant values is not supported.

Using custom errors#

Return custom errors, as you would with any other error type:

#[init(contract = "my_contract")]
fn contract_init_my(
    _ctx: &InitContext,
    _state_builder: &mut StateBuilder,
) -> Result<State, MyError> { Err(MyError::ErrOne) }

#[receive(contract = "my_contract", name = "my_receive")]
fn contract_receive_my(
    _ctx: &ReceiveContext,
    _host: &Host<State>
) -> Result<MyReturnValue, MyError> { Err(MyError::ErrTwo) }

Note

Adding schemas to your errors makes them more useful in concordium-client and cargo-concordium.

Was this article helpful?
Legal information