TRON GOBLIN
explorerv0.3-beta
MAINNET
block #0
Explorer / Blog / Common Tron transaction errors and what they actually mean

Common Tron transaction errors and what they actually mean

A field guide to the error codes you see when a Tron transaction fails — OUT_OF_ENERGY, REVERT, TAPOS_ERROR, CONTRACT_VALIDATE_ERROR — what each one is telling you and how to fix it.

A Tron transaction can fail in two very different places, and the difference matters for debugging. Either the network refuses to accept it (a validation error, returned synchronously on broadcast) or it's accepted, included in a block, and then fails during execution (an execution error, recorded in the receipt). The error names are different in each case, and they fail differently in your wallet.

This is a field guide to the ones you'll actually encounter — what they're saying, why they happen, and how to fix them.

The two-stage error model

Every transaction goes through validation before it's broadcast to the network, and then through execution once it lands in a block. The same transaction can clear validation cleanly and still fail execution — that's the case where a tx exists on-chain but didn't do anything.

StageWhat it checksWhere you see it
ValidationSignature, account exists, balance, resource quota, formatSynchronous error from your wallet / RPC node
ExecutionContract bytecode runs to completion or revertscontractRet field in the transaction receipt

Validation errors never leave a record on chain. Execution errors do — and they still burn the resources you consumed up to the point of failure. This is the most common confusion: a failed contract call still costs you energy.

Validation errors (rejected before broadcast)

These are returned by the node's BroadcastTransaction RPC. They mean nothing made it into a block, and you weren't charged. The error codes come from Tron's protobuf and you'll see them verbatim in wallet error messages.

CONTRACT_VALIDATE_ERROR

The most generic validation failure. The transaction's contract payload didn't pass pre-flight checks. The accompanying message string is the actual signal — read it. Common variants:

  • Validate TransferContract error, balance is not sufficient — your TRX balance is below the amount you tried to send (or below the burn fee, if you have no free bandwidth and no stake).
  • Account does not exist — Tron requires a destination account to be activated. If the receiver address has never been touched on-chain, the first deposit must include the 1 TRX activation fee. Most wallets handle this transparently; you'll only see it if you're crafting transactions manually.
  • Validate transferAsset error, asset balance is not sufficient — same as the TRX case but for a TRC10 token.
  • Invalid permission_id — you're trying to use a multi-sig permission that doesn't exist or doesn't grant the contract type you're signing.

CONTRACT_EXE_ERROR

Mid-execution validation — usually means the smart-contract preconditions are wrong. For example, calling an admin-only method from a non-admin address often surfaces here rather than as a REVERT, depending on the contract. Read the message.

BANDWITH_ERROR

Yes, that's the actual spelling in Tron's protobuf — BANDWITH, missing the D. It means you didn't have enough bandwidth (free quota + staked + burn-available) to broadcast the transaction. Either wait for the daily 1,500-point free refill, stake a small amount for daily bandwidth, or hold enough TRX in your account that the network can burn it for the byte fee.

TAPOS_ERROR

TAPOS = Transaction As Proof Of Stake. Every Tron transaction references a recent block hash to prove the signer saw recent state. The reference block is encoded in ref_block_bytes and ref_block_hash. If your transaction references a block that's been orphaned (or one that's too old), validation fails.

In practice this means: the transaction was crafted with a stale reference and sat around too long before being broadcast. Re-sign it with a current block reference and try again. Most wallets handle this automatically by using the latest block at signing time.

TRANSACTION_EXPIRATION_ERROR

Tron transactions carry an expiration timestamp — typically 60 seconds after signing. If you submit one past expiration, the node rejects it. This happens when a wallet queues a signed tx for offline broadcast and the user comes back too late, or when network congestion delays propagation past the deadline. Re-sign and resubmit.

DUP_TRANSACTION_ERROR

The network has already seen this exact transaction. Common cause: your wallet retried because the first broadcast appeared to fail (e.g. timeout), but it actually succeeded. Before resending, search the transactions feed or your address page for the hash — the original is almost always there.

TOO_BIG_TRANSACTION_ERROR

Transactions can't exceed ~500KB. You'll only hit this if you're deploying a large contract or batching a huge number of operations into one transaction. Split into smaller transactions.

SIGERROR

Signature verification failed. Either the signature was malformed, signed with the wrong key for the claimed sender, or the transaction hash you signed doesn't match the bytes you submitted. With a normal wallet this is rare; if you're crafting transactions manually, check that you're hashing the canonical serialized raw_data, not the wrapped transaction.

Execution errors (failed after inclusion)

These show up in the receipt as the contractRet field, alongside the energy and bandwidth that were consumed. The transaction exists on chain, your resources are spent, and the contract state changes were rolled back.

OUT_OF_ENERGY

The most common execution failure. Your transaction didn't allocate enough energy (via stake, rent, or fee_limit burn) to complete the contract call. Tron consumed everything you gave it and aborted the execution mid-flight.

The fix is usually one of:

  • Raise fee_limit — it caps how much TRX the network is allowed to burn for energy. If the cap is too low, the call dies early. Most wallets default to something like 100 TRX, which is plenty for transfers but tight for some DeFi operations.
  • Make sure you have the energy. Stake for it, rent it on an energy market, or hold enough TRX to let the protocol burn for it.
  • Check the operation's actual cost against the live energy cost calculator — a USDT transfer is ~31k, a SunSwap swap is ~130k, a fresh contract deployment can be 500k+.

REVERT

The contract explicitly aborted with a REVERT opcode. This is the contract telling you "your call didn't pass my preconditions" — not a network failure. Tron-VM is EVM-compatible, so this is the same opcode Solidity emits for failed require(), revert(), and unmet modifier checks.

Many contracts include a reason string in the revert, which gets surfaced in the receipt's result field. Common messages on TRC20 contracts:

  • ERC20: transfer amount exceeds balance — sender doesn't hold what they're trying to move.
  • ERC20: transfer amount exceeds allowance — you're using a transferFrom path without sufficient approve() first. Run an approve.
  • ERC20: transfer to the zero address — recipient is 0x0, almost always a frontend bug.
  • blocked or blacklisted — sender or recipient is on the token's blocklist. USDT-TRC20 has Tether-controlled blacklisting; if either address is flagged, the contract refuses the transfer.

Energy is still consumed up to the revert point, but unused energy is refunded. Bandwidth is fully consumed.

OUT_OF_TIME

Smart contract execution has a per-block time budget — by default, a single contract call can't run for more than ~50ms of VM time. Exceed it and the execution aborts with OUT_OF_TIME. You'll see this on unbounded loops, recursive code, or operations that fan out into many sub-calls.

If a contract you're calling routinely hits this, the contract has a design problem — there's no way to "raise the time limit" client-side. Either split the operation across multiple transactions or get the contract author to bound the work.

BAD_JUMP_DESTINATION

The EVM bytecode tried to jump to a non-jumpable location. In practice this only happens with corrupt bytecode, certain compiler bugs, or hand-written assembly that's wrong. If you're calling a popular contract, it's not you — something is off with the contract's state or arguments. Worth filing as a bug to the contract maintainers with the failing tx hash.

STACK_OVERFLOW / STACK_UNDERFLOW

Tron-VM (and EVM) has a stack depth limit of 1024 frames. Contracts that call each other recursively, or do excessive internal calls, can exhaust it. Common in flash-loan or proxy-heavy DeFi. The fix is on the contract side, not yours.

JVM_STACK_OVER_FLOW

Distinct from STACK_OVERFLOW — this is the Java VM that runs the node hitting its stack limit while interpreting the smart contract. Rare. Usually triggered by pathologically deep contract nesting. Same fix path as above.

TRANSFER_FAILED

Set when a contract called address.transfer() or address.send() as part of its execution, and that internal transfer didn't succeed. The outer transaction reverts. Most common cause: the contract is trying to send TRX to an address that can't accept it (e.g. a contract whose fallback function reverts), or to an unactivated account without including the activation fee.

ILLEGAL_OPERATION / UNKNOWN

Catch-alls for "the VM saw something it couldn't interpret." Like BAD_JUMP_DESTINATION, this is almost always a contract-side issue, not a caller issue. Report with the tx hash.

Token-specific gotchas

Some failures don't fit cleanly into the validation/execution split because they're about how a specific contract behaves.

"I sent USDT but it failed"

Almost always one of:

  • No TRX in the sender for energy. USDT-TRC20 transfers cost ~31k energy. With no stake or rent, the protocol burns TRX to pay for it. If you're holding USDT but no TRX, the transfer can't pay for itself and fails at validation with balance is not sufficient. Send some TRX to the address first.
  • fee_limit too low. If your wallet caps energy spending too aggressively, the tx fails with OUT_OF_ENERGY. Raise the cap.
  • Blacklisted address. Either side flagged by Tether. The receipt will show REVERT with a blocked message.

"My swap on SunSwap reverted"

Usually slippage. Routers reject swaps where the output would be worse than your amountOutMin parameter — common during volatile periods. The revert message is typically INSUFFICIENT_OUTPUT_AMOUNT or EXCESSIVE_INPUT_AMOUNT. Widen your slippage tolerance and retry. If it keeps reverting at high slippage, the pool may be drained or paused.

"Approve transaction succeeded but transferFrom still fails"

Some legacy TRC20 contracts (including USDT for a long time) refuse to approve() from a non-zero allowance to another non-zero allowance — you have to approve(0) first, then approve(new_value). If your transferFrom keeps reverting with an allowance error despite a fresh approve, this is the cause. Reset to zero, then set.

How to read a failed tx on Tron Goblin

Open the transaction in the tx feed or paste the hash directly. A failed tx will show:

  • Statusfailed, with the protocol error code (e.g. OUT_OF_ENERGY) right next to it.
  • contractRet field — the raw VM result. Matches one of the strings from this post.
  • result message (when present) — the revert reason string, if the contract emitted one. This is usually what tells you the actual problem.
  • Energy used — how much energy the tx consumed before failing. Useful for setting a better fee_limit on the retry.

TL;DR cheatsheet

ErrorWhat to do
OUT_OF_ENERGYRaise fee_limit, stake, or rent energy. Check actual cost.
REVERTRead the message. Usually a contract precondition you didn't meet.
OUT_OF_TIMEContract execution too slow. Not fixable client-side.
TAPOS_ERRORReference block stale. Re-sign with a current block.
TRANSACTION_EXPIRATION_ERRORSubmitted too late after signing. Re-sign and resubmit.
BANDWITH_ERRORNo bandwidth and no TRX to burn for it. Wait for daily refill or stake.
CONTRACT_VALIDATE_ERRORRead the message — usually balance, account, or permission issue.
DUP_TRANSACTION_ERRORAlready broadcast. Search for the hash before retrying.
SIGERRORSignature doesn't match. Check what you're hashing.
BAD_JUMP_DESTINATION, STACK_*, ILLEGAL_OPERATIONContract-side bug. Report with the tx hash.

The single most useful habit: when a tx fails, open it on chain and read the contractRet plus the result message before guessing. The network is telling you what went wrong — almost always literally.