Error Handling

23.1 Aborts

Move has no exceptions or try/catch. An abort terminates the transaction and reverts all its effects; gas consumed so far is still charged.

abort 42;                          // abort with a u64 code
assert!(amount > 0, EZeroAmount);  // abort with code if condition is false
assert!(ok);                       // Sui 2024 / recent Aptos: code optional

23.2 Error constants

Aptos code often wraps codes with std::error categories so the canonical error appears in explorers:

std::error helper Caller passed a bad value Index/amount out of range Wrong state for this operation unauthenticated / permission_denied not_found / already_exists

Aptos also lets you document errors with doc comments (/// Caller is not the owner) which tooling surfaces in error messages.

// Sui convention: EPascalCase
const ENotOwner: u64 = 0;
const EInsufficientBalance: u64 = 1;

// Aptos convention: E_UPPER_SNAKE plus std::error categories
const E_NOT_OWNER: u64 = 1;
use std::error;
assert!(owner == addr, error::permission_denied(E_NOT_OWNER));
assert!(exists<Counter>(addr), error::not_found(E_NOT_FOUND));

23.3 Clever errors: #[error] (Sui)

With #[error], the abort code encodes the constant's identity and line number, so the CLI, SDKs, and explorers can display the human-readable message. The constant can be any constant type (commonly vector<u8> strings).

#[error]
const ENotOwner: vector<u8> = b"Only the owner can perform this action";

public fun withdraw(v: &mut Vault, ctx: &TxContext) {
    assert!(v.owner == ctx.sender(), ENotOwner);
}

23.4 Abort semantics for common operations

Arithmetic overflow, division by zero, bad cast Arithmetic error abort Out-of-bounds vector access

move_from/borrow_global of missing resource (Aptos) Abort (MISSING_DATA)

move_to when resource already exists (Aptos) Abort (RESOURCE_ALREADY_EXISTS)

option::extract on none / destroy_some on none Transaction fails; gas charged

23.5 Designing errors

Validate inputs at the start of a function (fail fast, cheaper gas).

Use one constant per distinct failure; never reuse codes for different meanings.

Return Option/bool for expected outcomes instead of aborting when callers may want to recover (callers cannot catch aborts).