Exit codes
Each transaction on TON Blockchain consists of multiple phases. An exit code is a -bit signed integer, which indicates whether the compute or action phase of the transaction was successful, and if not — holds the code of the exception occurred. Each exit code represents its own exception or resulting state of the transaction.
Exit codes and indicate normal (successful) execution of the compute phase. Exit (or result) code indicates normal (successful) execution of the action phase. Any other exit code indicates that a certain exception has occurred and that the transaction wasn’t successful in one way or another, i.e. transaction was reverted or the inbound message has bounced back.
TON Blockchain reserves exit code values from to , while Tact utilizes exit codes from to . Note, that exit codes used by Tact indicate contract errors which can occur when using Tact-generated FunC code, and are therefore thrown in the transaction’s compute phase and not during the compilation.
The range from to is free for developer-defined exit codes.
Table of exit codes
The following table lists exit codes with an origin (where it can occur) and a short description for each. The table doesn’t list the exit code of the require()
, as it generates it depending on the concrete error
message String.
Exit code | Origin | Brief description |
---|---|---|
Compute and action phases | Standard successful execution exit code. | |
Compute phase | Alternative successful execution exit code. Reserved, but doesn’t occur. | |
Compute phase | Stack underflow. | |
Compute phase | Stack overflow. | |
Compute phase | Integer overflow. | |
Compute phase | Range check error — some integer is out of its expected range. | |
Compute phase | Invalid TVM opcode. | |
Compute phase | Type check error. | |
Compute phase | Cell overflow. | |
Compute phase | Cell underflow. | |
Compute phase | Dictionary error. | |
Compute phase | Described in TVM docs as “Unknown error, may be thrown by user programs”. | |
Compute phase | Fatal error. Thrown by TVM in situations deemed impossible. | |
Compute phase | Out of gas error. | |
Compute phase | Same as . Negative, so that it cannot be faked. | |
Compute phase | VM virtualization error. Reserved, but never thrown. | |
Action phase | Action list is invalid. | |
Action phase | Action list is too long. | |
Action phase | Action is invalid or not supported. | |
Action phase | Invalid source address in outbound message. | |
Action phase | Invalid destination address in outbound message. | |
Action phase | Not enough Toncoin. | |
Action phase | Not enough extra currencies. | |
Action phase | Outbound message does not fit into a cell after rewriting. | |
Action phase | Cannot process a message — not enough funds, the message is too large or its Merkle depth is too big. | |
Action phase | Library reference is null during library change action. | |
Action phase | Library change action error. | |
Action phase | Exceeded maximum number of cells in the library or the maximum depth of the Merkle tree. | |
Action phase | Account state size exceeded limits. | |
Tact compiler (Compute phase) | Null reference exception. | |
Tact compiler (Compute phase) | Invalid serialization prefix. | |
Tact compiler (Compute phase) | Invalid incoming message — there’s no receiver for the opcode of the received message. | |
Tact compiler (Compute phase) | Constraints error. Reserved, but never thrown. | |
Tact compiler (Compute phase) | Access denied — someone other than the owner sent a message to the contract. | |
Tact compiler (Compute phase) | Contract stopped. Reserved, but never thrown. | |
Tact compiler (Compute phase) | Invalid argument. | |
Tact compiler (Compute phase) | Code of a contract was not found. | |
Exit codes in Blueprint projects
In Blueprint tests, exit codes from the compute phase are specified in the exitCode
field of the object argument for toHaveTransaction()
method of expect()
matcher. The field for the result codes (exit codes from the action phase) in the same toHaveTransaction()
method is called actionResultCode
.
Additionally, one can take a look at the result of sending a message to a contract and discover the phases of each transaction and their values, including exit (or result) codes for compute phase (or action phase).
Note, that in order to do so, you’ll have to do a couple of type checks before that:
Compute and action phases
0: Normal termination
This exit (or result) code indicates a successful completion of the compute (or action) phase of the transaction.
Compute phase
TVM initialization and all computations occur in the compute phase.
If the compute phase fails (the resulting exit code isn’t or ), the transaction skips the action phase and goes to the bounce phase. In it, the bounce message is formed for the transactions initiated by the inbound message.
1: Alternative termination
This is an alternative exit code for the successful execution of the compute phase. Reserved, but never occurs.
2: Stack underflow
If some operation consumed more elements than there were on the stack, the error with exit code is thrown: Stack underflow
.
3: Stack overflow
If there are too many elements copied into a closure continuation, an error with exit code is thrown: Stack overflow
. Occurs rarely, unless you’re deep in Fift and TVM assembly trenches:
4: Integer overflow
If the value in calculation goes beyond the range from to inclusive, or there’s an attempt to divide or modulo by zero, an error with exit code is thrown: Integer overflow
.
5: Integer out of range
Range check error — some integer is out of its expected range. I.e. any attempt to store an unexpected amount of data or specify an out-of-bounds value throws an error with exit code : Integer out of range
.
Examples of specifying an out-of-bounds value:
6: Invalid opcode
If you specify an instruction that is not defined in the current TVM version or try to set an unsupported code page, an error with exit code is thrown: Invalid opcode
.
7: Type check error
If an argument to a primitive is of an incorrect value type or there’s any other mismatch in types during the compute phase, an error with exit code is thrown: Type check error
.
8: Cell overflow
From Cells, Builders and Slices page of the Book:
Cell
is a primitive and a data structure, which ordinarly consists of up to continuously laid out bits and up to references (refs) to other cells.
To construct a Cell
, a Builder
is used. If you try to store more than bits of data or more than references to other cells, an error with exit code is thrown: Cell overflow
.
This error can be triggered by manual construction of the cells via relevant .loadSomething()
methods or when using Structs and Messages and their convenience methods.
9: Cell underflow
From Cells, Builders and Slices page of the Book:
Cell
is a primitive and a data structure, which ordinarly consists of up to continuously laid out bits and up to references (refs) to other cells.
To parse a Cell
, a Slice
is used. If you try to load more data or references than Slice
contains, an error with exit code is thrown: Cell underflow
.
The most common cause of this error is a mismatch between the expected and actual memory layouts of the cells, so it’s recommended to use Structs and Messages for parsing of the cells instead of manual parsing via relevant .loadSomething()
methods.
10: Dictionary error
In Tact, the map<K, V>
type is an abstraction over the “hash” map dictionaries of FunC and underlying HashmapE
type of TL-B and TVM.
If there is an incorrect manipulation of dictionaries, such as improper assumptions about their memory layout, an error with exit code is thrown: Dictionary error
. Note, that Tact prevents you from getting this error unless you do Fift and TVM assembly work yourself:
11: “Unknown” error
Described in TVM docs as “Unknown error, may be thrown by user programs”, although most commonly used for problems with queueing a message send or problems with get-methods.
12: Fatal error
Fatal error. Thrown by TVM in situations deemed impossible.
13: Out of gas error
If there isn’t enough gas to end computations in the compute phase, the error with exit code is thrown: Out of gas error
.
But this code isn’t immediately shown as is — instead, the bitwise NOT operation is applied, which changes the value from to . And only then the code is shown.
That’s done in order to prevent the resulting code () from being produced artificially in user contracts, since all functions that can throw an exit code can only specify integers in the range from to inclusive.
-14: Out of gas error
See exit code 13.
14: Virtualization error
Virtualization error, related to prunned branch cells. Reserved, but never thrown.
Action phase
The action phase is processed after the successful execution of the compute phase. It attempts to perform the actions stored into the action list by TVM during the compute phase.
Some actions may fail during processing, in which case those actions may be skipped or the whole transaction may revert depending on the mode of actions. The code indicating the resulting state of the action phase is called a result code. Since it’s also a -bit signed integer that essentially serves the same purpose as exit code of compute phase, it’s common to call the result code an exit code too.
32: Action list is invalid
If the list of actions contains exotic cells, an action entry cell does not have references or some action entry cell couldn’t be parsed, an error with exit code is thrown: Action list is invalid
.
33: Action list is too long
If there are more than actions queued for execution, the action phase will throw an error with an exit code : Action list is too long
.
34: Invalid or unsupported action
There are only four supported actions at the moment: changing the contract code, sending a message, reserving a specific amount of nanoToncoins and changing the library cell. If there’s any issue with the specified action (invalid message, unsupported action, etc.), an error with exit code is thrown: Invalid or unsupported action
.
35: Invalid source address in outbound message
If the source address in the outbound message isn’t equal to addr_none
or to the address of the contract that initiated this message, an error with exit code is thrown: Invalid source address in outbound message
.
36: Invalid destination address in outbound message
If the destination address in the outbound message is invalid, e.g. it doesn’t conform to the relevant TL-B schemas, contains unknown workchain ID or it has invalid length for the given workchain, an error with exit code is thrown: Invalid destination address in outbound message
.
37: Not enough Toncoin
If all funds of the inbound message with base mode 64 set had been already consumed and there’s not enough funds to pay for the failed action, or the TL-B layout of the provided value (CurrencyCollection
) is invalid, or there’s not enough funds to pay forward fees or not enough funds after deducting fees, an error with exit code is thrown: Not enough Toncoin
.
38: Not enough extra currencies
Besides the native currency, Toncoin, TON Blockchain supports up to extra currencies. They differ from making new Jettons because extra currencies are natively supported — one can potentially just specify an extra HashmapE
of extra currency amounts in addition to the Toncoin amount in the internal message to another contract. Unlike Jettons, extra currencies can only be stored and transferred and do not have any other functionality.
At the moment, there are no extra currencies on TON Blockchain, but the exit code in cases when there is not enough extra currency to send the specified amount of it is already reserved: Not enough extra currencies
.
39: Outbound message doesn’t fit into a cell
When processing the message, TON Blockchain tries to pack it according to the relevant TL-B schemas, and if it cannot an error with exit code is thrown: Outbound message doesn't fit into a cell
.
40: Cannot process a message
If there would not be enough funds to process all the cells in a message, the message is too large or its Merkle depth is too big, an error with exit code is thrown: Cannot process a message
.
41: Library reference is null
If the library reference was required during library change action, but it was null, an error with exit code is thrown: Library reference is null
.
42: Library change action error
If there’s an error during an attempt at library change action, an error with exit code is thrown: Library change action error
.
43: Library limits exceeded
If the maximum number of cells in the library is exceeded or the maximum depth of the Merkle tree is exceeded, an error with exit code is thrown: Library limits exceeded
.
50: Account state size exceeded limits
If the account state (contract storage, essentially) exceeds any of the limits specified in config param 43 of TON Blockchain by the end of the action phase, an error with exit code is thrown: Account state size exceeded limits
.
If the configuration is absent, default values are:
max_msg_bits
is equal to — maximum message size in bits.max_msg_cells
is equal to — maximum number of cells a message can occupy.max_library_cells
is equal to — maximum number of cells that can be used as library reference cells.max_vm_data_depth
is equal to — maximum cells depth in messages and account state.ext_msg_limits.max_size
is equal to — maximum external message size in bits.ext_msg_limits.max_depth
is equal to — maximum external message depth.max_acc_state_cells
is equal to — maximum number of cells that an account state can occupy.max_acc_state_bits
is equal to — maximum account state size in bits.max_acc_public_libraries
is equal to — maximum number of library reference cells that an account state can use on the masterchain.defer_out_queue_size_limit
is equal to — maximum number of outbound messages to be queued (regards validators and collators).
Tact compiler
Tact utilizes exit codes from to . Note, that exit codes used by Tact indicate contract errors which can occur when using Tact-generated FunC code, and are therefore thrown in the transaction’s compute phase and not during the compilation.
128: Null reference exception
If there’s a non-null assertion, such as the !!
operator, and the checked value is null
, an error with exit code is thrown: Null reference exception
.
129: Invalid serialization prefix
Reserved, but due to a number of prior checks it cannot be thrown unless one hijacks the contract code before deployment and changes the opcodes of the Messages expected to be received in the contract.
130: Invalid incoming message
If the received internal or external message isn’t handled by the contract, an error with exit code is thrown: Invalid incoming message
. It usually happens when the contract doesn’t have a receiver for the particular message and its opcode prefix (32-bit integer header).
Consider the following contract:
If you try to send any message, except for Deploy
provided by @stdlib/deploy
, the contract won’t have a receiver for it and thus would throw an error with exit code .
131: Constraints error
Constraints error. Reserved, but never thrown.
132: Access denied
If you use the Ownable
trait from the @stdlib/ownable
library, the helper function requireOwner()
provided by it will throw an error with exit code if the sender of the inbound message won’t match the specified owner: Access denied
.
133: Contract stopped
A message has been sent to a stopped contract. Reserved, but never thrown.
134: Invalid argument
If there is an invalid or unexpected argument value, an error with exit code is thrown: Invalid argument
.
Here are some of the functions in Tact which can throw an error with this exit code:
-
Int.toFloatString(digits)
: if thedigits
is not in the interval:digits
. -
String.fromBase64()
andSlice.fromBase64()
: if the givenString
orSlice
contains non-Base64 characters.
135: Code of a contract was not found
If the code of the contract doesn’t match the one saved in TypeScript wrappers, the error with exit code will be thrown: Code of a contract was not found
.
136: Invalid address
Removed since Tact 1.6A value of type Address
is valid in Tact when:
- It occupies bits: bits for the chain ID prefix and bits for the address itself.
- It belongs to either basechain (ID ) or masterchain (ID ).
If the Address
isn’t valid, the error with exit code will be thrown: Invalid address
.
137: Masterchain support is not enabled for this contract
Removed since Tact 1.6Prior to removal, any attempts to point to masterchain (ID ) or otherwise interact with it without enabling masterchain support were throwing an exception with exit code : Masterchain support is not enabled for this contract
.