Error Handling

Recoverable Errors

Recoverable errors represent expected faults. Similar to Rust, Sway expresses recoverable errors by using the std::result::Result enum, letting you propagate or transform the error without immediately reverting the transaction.

To learn more about expressing and handling recoverable errors, see the chapter on Result<T, E> enum.

Irrecoverable Errors

Irrecoverable errors indicate bugs or violated invariants. They trigger a VM-wide revert that atomically rolls back every state change in the transaction, and it cannot be caught or handled in Sway code, signaling that the program cannot sensibly continue.

panic Expression

The recommended way of expressing an irrecoverable errors is to use the panic expression:

if some_error_occurred {
    panic "Some error has occurred.";
}

At runtime, the panic expression aborts and reverts the execution of the entire program. At compile time, for each panic encountered in code, Sway compiler will generate a unique revert code and create an entry in the ABI JSON errorCodes section. The generated errorCodes entry will contain the information about source location at which the panic occurs, as well as the error message.

This mechanism allows for getting a rich troubleshooting information, without an additional on-chain cost. The generated bytecode will contain only the revert instruction, and the remaining information, the error message and the error location, are stored off-chain, in the ABI JSON file.

For example, let's assume that the above code is situated in the module some_module, contained within the version v1.2.3 of the package some_package.

At runtime, the panic will result in a compiler generated revert code, e.g., 18446744069414584323. At compile time, an entry similar to this will be added to the ABI JSON errorCodes section:

"errorCodes": {
    "18446744069414584323": {
        "pos": {
          "pkg": "some_package@1.2.3",
          "file": "some_module.sw",
          "line": 13,
          "column": 9
        },
        "logId": null,
        "msg": "Some error has occurred."
    },
}

Rust and TypeScript SDK, as well as forc test, recognize revert codes generated from panic expressions. E.g., if a Sway unit test fails because of a revert caused by the above panic line, the forc test will display the following:

test some_test, "path/to/failing/test.sw":42
    revert code: ffffffff00000003
    ├─ panic message: Some error has occurred.
    └─ panicked in:   some_package@1.2.3, src/some_module.sw:13:9

Error Types

Passing textual error messages directly as a panic argument is the most convenient way to provide a helpful error message. It is sufficient for many use-cases. However, often we want:

  • to provide an additional runtime information about the error.
  • group a certain family of errors together.

For these use-cases, you can use error types. Error types are enums annotated with the #[error_type] attribute, whose all variants are attributed with the #[error(m = "<error message>")] attributes. Each variant represent a particular error, and the enum itself the family of errors. The convention is to postfix the names of error type enums with Error.

For example, let's assume we are checking if a provided Identity has certain access rights to our contract. The error type enum representing access rights violations could look like:

#[error_type]
pub enum AccessRightError {
    #[error(m = "The provided identity is not an administrator.")]
    NotAnAdmin: Identity,
    #[error(m = "The provided identity is not an owner.")]
    NotAnOwner: Identity,
    #[error(m = "The provided identity does not have write access.")]
    NoWriteAccess: Identity,
}

where each Identity represents the actual, provided identity.

In code, we can now check for access rights and panic if they are violated:

fn do_something_that_requires_admin_access(admin: Identity) {
    if !is_admin(admin) {
        panic AccessRightError::NotAnAdmin(admin);
    }

    // ...
}

Assuming we have a failing test for the above function, the test output will show the error message, but also the provided Identity. E.g.:

test some_test_for_admin_access, "path/to/failing/test.sw":42
    revert code: ffffffff00000007
    ├─ panic message: The provided identity is not an administrator.
    ├─ panic value:   NotAnAdmin(Address(Address()))
    └─ panicked in:   some_other_package@0.1.0, src/admin_module.sw:11:9