Why your sui programmable transaction block failed with executionerror
If a Sui Programmable Transaction Block (PTB) fails, the error ExecutionError is the generic wrapper Sui returns when a command inside the block cannot complete. It is not a single, specific fault; it is the network's way of saying "one of the steps you requested violated the rules of the move function, the object graph, or the gas schedule." The answer to why it failed is almost always found in the error's nested ExecutionFailureStatus, which contains the precise reason. You fix it by reading that inner status, identifying which command in the block triggered it, and correcting the move call, the object reference, or the input value.
What an executionerror actually tells you
A PTB is a list of commands: move calls, split or merge operations, transfers, or even other PTBs. The Sui validator processes these commands in sequence, but it does not necessarily execute them one at a time. Instead, it checks the entire block for validity against the current state, then simulates or executes it. When something fails, the client SDK (Rust, TypeScript, or the CLI) surfaces an ExecutionError object.
That object has two parts of interest:
tx_sign_effects- the effects of the transaction up to the point of failure (or the full effects if it succeeded).status- aFailurevariant containingExecutionFailureStatus.
The ExecutionFailureStatus is an enum with dozens of variants. Common ones include:
InsufficientGasMoveAbort(with aMoveLocationand aMoveAbortCode)ObjectFetcherObjectNotExistCoinBalanceOverflowInvalidSharedChildMovePrimitiveRuntimeError
Your first step, always, is to print the full error object. Do not rely on the top-level message. The CLI does this when you add --json. In TypeScript, log the effects field. The inner status is the actual diagnosis.
Step-by-Step: reading the failure
-
Reproduce the failure with full output. Run the transaction again with
sui client callorsui client ptband add--json(or--dumpfor the CLI). Capture the entire error object. -
Locate
ExecutionFailureStatus. In the JSON, find"status": {"ExecutionError": {"error": ...}}. Theerrorfield contains the variant. -
Find the
command_index. The error object usually includes acommand_indexfield. This tells you which command in your PTB (0-based) failed. If you built the PTB programmatically, this maps directly to the order you added commands. -
Look for nested details. For
MoveAbort, you will see aMoveLocation(the module, function, and bytecode offset) and aMoveAbortCode. For object errors, you will see anObjectIDorObjectVersion. For gas errors, you will see the balance and required cost. -
Fix the root cause, not the symptom. The most common causes are: passing an object by value when it was already used (moved) earlier in the block; referencing an object version that no longer exists (often because a previous command in the same block created or mutated it); passing a
Coinobject that does not have enough balance for a split or transfer; or calling a function with an argument that violates an assertion in the Move code.
The three most common root causes
1. Object Version or ID Mismatch
Sui objects are immutable references to a specific version. If you fetch an object, then a previous command in the same PTB mutates or transfers that object, the later command that references the old version will fail with ObjectFetcherObjectNotExist or ObjectReadError. This is not a race condition; it is the system correctly refusing to let you use a stale reference.
Fix: Fetch the object again after the mutation, or restructure the PTB so you do not need the old version. For example, if you split a coin and then want to use the original coin, you must use the version returned from the split command, not the one you fetched before the PTB started.
2. MoveAbort with a Non-Zero Code
A MoveAbort means the Move function you called hit an abort statement. The code is a u64 that the module's author defined. It is not a Sui error; it is an application-level error. For example, a DEX might abort with code 1 for "insufficient liquidity" and code 2 for "slippage too high".
Fix: Look up the abort code in the module's documentation or source. If the module is on-chain, you can sui client call the move view function if the author exposes one, or read the module's bytecode with sui move disassemble (requires the package source). A common cause is passing a value of zero where the function requires a positive integer, or passing a list that is empty.
3. Gas and Coin Balance Issues
InsufficientGas is straightforward: the PTB ran out of gas. But a subtler failure is CoinBalanceOverflow or CoinDenyList errors. If you are splitting a coin, the total of all splits must equal the original balance. If you try to split a coin into amounts that sum to more than the balance, you get a failure.
Fix: For gas, increase the gas_budget (not the coin value) and retry. For split errors, check your arithmetic. For CoinDenyList, the coin you are using is on a deny list for the specific address or the network; this is rare but possible on Sui testnets.
When the Error Is Not in the Status
Sometimes the ExecutionError is not a failure of your commands but of the transaction itself. For example:
InvalidGasObject- the gas object you provided is not aCoin<SUI>or is not owned by the sender.InvalidGasPrice- the gas price you set is below the minimum or above the maximum for the current epoch.EffectWriteSetError- a system-level issue, usually a bug in the validator, not your code.
For these, check the network's current gas parameters and your sender's ownership. The fix is usually to resubmit with a different gas object or price.
A worked example (pseudocode)
Assume you have a PTB that does the following:
1. Call `balance_of(account)` -> returns a coin.
2. Split that coin into two.
3. Transfer one split to address A.
4. Transfer the other split to address B.
If step 2 fails, the error will say MoveAbort or CoinBalanceOverflow. If step 3 fails because the coin was already transferred in step 2, you will see ObjectNotTransferable or ObjectUsed. The command index will point to step 3, but the fix is to realize you transferred the original object, not a copy.
Practical Checklist
- Print the full JSON error. Never guess from the message.
- Identify the
command_index. It tells you exactly which line of your PTB failed. - For
MoveAbort, look up the code in the module's source. - For object errors, check whether a prior command in the same PTB consumed or mutated the object.
- For gas errors, raise the budget or check the gas object's balance.
- If the error is
ExecutionFailureStatuswith a variant you do not recognize, search the Sui documentation or thesui-sdksource for that variant's meaning.
The Sui documentation on PTB commands and the sui-errors crate (in Rust) list all possible statuses. Reading those two pages will resolve most of your issues faster than trial and error.
Not financial advice. suiboxer.xyz publishes market data and general information about digital assets. Crypto assets are volatile and you can lose everything you put in. Nothing here is a recommendation to buy, sell or hold, and we make no price predictions.
Prices are sourced from third parties and may be delayed or wrong. Verify anything you intend to act on against a primary source.