Skip to content

Exceptions ​

On Tezos, exceptions cannot be caught; there is no way to intercept exceptions and trigger alternate behavior. If an exception occurs, the entire transaction is backtracked. In this case, all of the operations are canceled and any completed operations are reverted, as if the initial call to the contract never happened.

For this reason, code in SmartPy modules cannot use the standard Python try/except block.

INFO

A transaction starts with a call from a user account (sometimes known as an implicit account) and includes all subsequent operations, such as transfers, contract calls, and contract originations that the initial call triggered.

For example, if a user account calls contract A, contract A calls contract B, contract B calls contract C, and contract C raises an exception, all calls are reverted, including the original call to contract A. The storage states of all of these contracts and the balances of all related accounts are set back to their state before the original call, as if that call never happened.

raise  x: t → 

Aborts the current transaction and raises an error x of type t.

smartpy
raise "NotAdmin"
raise ("TOKEN_UNDEFINED", 404)
assert  x: bool, exception: t → 

Checks that x evaluates to True and raises an exception if it doesn’t.

smartpy
assert sp.sender == self.data.administrator, "NotAdmin"

Error messages ​

Give each failure an error message of its own. Without one, the compiled contract fails with a value that the exceptions flag generates: under the default flag, verify-or-line, that value is the number of the line of the failure in the SmartPy source file, except for an assert, which fails with its condition. This number is not a line of the compiled Michelson: the deployed contract does not tell which source line it refers to, so someone who calls the contract cannot read it without the SmartPy source of that very version. It also changes whenever the lines above it move.

These statements and functions take an error message:

smartpy
assert sp.sender == self.data.administrator, "NotAdmin"
raise "NotAdmin"
x = self.data.price.unwrap_some(error="NoPrice")
x = self.data.balances.get(owner, error="UnknownOwner")
v = self.data.shape.unwrap.Rectangle(error="NotARectangle")

Some failures cannot take a message: a mutez underflow, a division by zero, a sp.range of step 0, tickets that cannot be split or joined. When such a failure must tell what went wrong, check its operands with an assert first:

smartpy
assert self.data.balance >= amount, "InsufficientBalance"
self.data.balance -= amount

Exception flags ​

You can control the text of error messages with scenario flags to provide more information while debugging or less information to save fees. See Test scenarios for more information.