Errors and debugging

How TRON API errors are reported, the three error categories (HTTP-level, validation, execution), how to decode hex-encoded validation messages, retry strategy and idempotency, and the debugging endpoints to confirm what actually happened.

TRON API errors fall into three categories with different debugging procedures:

  • HTTP-level errors — network or transport failures before the request reaches the node
  • Validation errors — the node rejected the transaction before execution; the broadcast response classifies it with a top-level code such as CONTRACT_VALIDATE_ERROR, SIGERROR, or BANDWITH_ERROR, plus a message whose representation depends on visible
  • Execution errors — the transaction was accepted into a block but the on-chain execution failed; reported in the transaction info, not the broadcast response

Each category has different debugging steps and different retry implications. Confusing them is a common production bug; for example, creating a replacement while the original broadcast outcome is still unknown can produce duplicate balance changes if both transactions are eventually included successfully.

📘

Prerequisites


Category 1: HTTP-level errors

The request did not complete a round trip — the client never got a JSON response from the node.

SymptomLikely causeAction
Connection refusedWrong endpoint, node downVerify URL; failover to another node
5xx responseNode-side problem (overload, internal error)Retry reads with backoff. For writes, first determine whether the request was processed; fail over if the endpoint remains unavailable
4xx responseBad request URL, missing header, malformed JSONInspect request; fix client
Request timeoutNode slow, network slow, query too expensiveRetry reads with a longer timeout. A write has an unknown outcome and must be checked before retrying; split expensive queries or use TronGrid extension APIs
401, 403API key missing or wrong (TronGrid only)See TronGrid for the API-key flow
429Rate-limited (TronGrid only)Back off; check plan limits

Not receiving a business response does not prove that the node never received or processed the request. Reads are generally safe to retry. For transaction broadcasts, re-broadcast the same signed transaction so its txID remains unchanged. For other state-changing requests, check node or on-chain state before deciding whether to retry.


Category 2: Validation errors

The node received the request, parsed it, but rejected it at the validation stage. The transaction never enters the mempool.

When the underlying result is false, /wallet/broadcasttransaction normally omits the result field. Use code and message to identify the failure:

{
  "code": "CONTRACT_VALIDATE_ERROR",
  "message": "636f6e7472616374207061726168657920646f6573206e6f74206d61746368"
}

The code field gives the broad failure category. The message field provides the specific cause. When visible is omitted or false, the node normally returns this field as hex; with visible: true, it may return UTF-8 text.

Common top-level broadcast codes

codeMeaningAction
CONTRACT_VALIDATE_ERRORThe transaction data or current chain state failed contract validationDecode message, then correct the parameters or account state
SIGERRORTransaction signature validation failedCheck the key and signing algorithm, and ensure raw_data was not modified after signing
BANDWITH_ERRORThe account lacks sufficient Bandwidth, or lacks enough TRX to pay pre-execution costs such as Bandwidth, new-account creation, multisig, or memo feesAdd Bandwidth or TRX; also check whether the transaction creates an account or includes multisig or memo fees

BANDWITH_ERROR preserves the spelling used by the protocol enum; clients must match this exact value.

Decoding a hex-encoded message

const message = "636f6e7472616374207061726168657920646f6573206e6f74206d61746368";
const decoded = /^(?:[0-9a-fA-F]{2})+$/.test(message)
  ? Buffer.from(message, "hex").toString("utf8")
  : message;
// "contract parahey does not match"

Most SDKs decode automatically. If you process the HTTP response directly, detect the representation before decoding so that a plain-text message is not misinterpreted as hex.

Common validation error subtypes

Decoded message (typical)CauseFix
account does not existThe signing or recipient address has never been activated on-chainActivate the account by sending it a small TRX amount first
balance is not sufficientInsufficient TRX for the operationTop up; check fee budget
signature errorSignature verification failedLikely encoding mismatch — see Encoding; also check that raw_data was not modified after construct
Transaction expiredThis submission failed the node's raw_data.expiration check and cannot enter the pending poolCompare expiration with the node's current chain head. If it is earlier than the next eligible block slot, rebuild and sign a fresh transaction. If it is more than approximately 24 hours ahead of the chain head, either wait for the head to advance, provided the transaction's TAPOS reference remains valid, or rebuild with an expiration inside the valid range. If the transaction may have been submitted earlier, first check the original txID using the solidified-state procedure below
Validate ... contract error, ...Contract-specific validation failedRead the rest of the message; often parameter-shape mismatch
frozenBalance must be positiveStake amount is zero or negativeSend a positive integer in sun
delegateBalance must be greater than or equal to 1 TRXDelegation below minimumIncrease amount

Retry a validation failure only after correcting its cause. A fresh transaction is not automatically safe when an earlier broadcast outcome is unknown; check whether the original txID was included before authorizing a replacement. Retrying the exact same signed payload succeeds only if the relevant validation conditions changed, such as after topping up the balance.


Category 3: Execution errors

A smart-contract transaction can pass node validation and be included in a block, yet still fail during TVM execution. The transaction receipt records this execution result. Query the following endpoint for the solidified result:

POST /walletsolidity/gettransactioninfobyid
{ "value": "<txid>" }

After receiving the response, first verify that the top-level result is not FAILED, then use receipt.result to determine the TVM execution outcome. The complete receipt.result enum contains 16 values and is defined in protocol/src/main/protos/core/Tron.proto:

receipt.resultEnumMeaning
DEFAULT0Initial value before execution completes (you rarely see this on a finalized transaction)
SUCCESS1Transaction executed successfully
REVERT2The TVM reverted (REVERT opcode, assert, require failure)
BAD_JUMP_DESTINATION3Invalid jump in bytecode
OUT_OF_MEMORY4OOM during execution
PRECOMPILED_CONTRACT5Error inside a precompiled contract
STACK_TOO_SMALL6Stack underflow — popped from an empty stack
STACK_TOO_LARGE7Pushed beyond the 1024-item stack limit
ILLEGAL_OPERATION8Illegal opcode or operation
STACK_OVERFLOW9Stack overflow in the VM
OUT_OF_ENERGY10The transaction ran out of Energy mid-execution
OUT_OF_TIME11Execution exceeded the per-transaction CPU time limit, or a specific protocol check triggered the result; inspect the exact error message
JVM_STACK_OVER_FLOW12JVM-side stack overflow (deep recursion in the VM implementation)
UNKNOWN13Unexpected error not captured by the categories above
TRANSFER_FAILED14An internal TRX or TRC-10 transfer failed
INVALID_CODE15Deployed contract bytecode failed validation

For REVERT, decode the revert reason from the transaction's contractResult[0] field — it follows Solidity's standard Error(string) ABI format.

Do not retry an execution error with the same signed payload. The transaction has already been included and executed, and resubmitting the same txID cannot produce a second execution. Diagnose the receipt, correct the cause, and then build and sign a new transaction.


Retry strategy

Different categories have different retry semantics. The summary:

CategoryCan the original request be retried directly?Strategy
Network error or timeoutDepends on the requestRetry reads with backoff. Re-broadcast only the same signed transaction; check the result before retrying other writes
5xx node errorDepends on the requestApply the same write-safety rules as for a timeout; switch endpoints if the failure persists
Rate-limited (429)YesBackoff respecting Retry-After; consider upgrading plan
Validation signature errorDo not rebroadcast a transaction with an invalid signature. If raw_data remains valid, correct the signature and retryCheck that each signing key matches the transaction permission, that the signature format is correct, and that raw_data was not modified after signing. If raw_data remains valid, leave it unchanged and collect valid signatures again. Because the txID is derived from raw_data, it remains unchanged. If raw_data has expired or must change, and another signed version may have been submitted successfully, check the original txID under the safe rebroadcast and replacement procedure before rebuilding
Validation Transaction expiredNot if expiration is earlier than the next eligible block time. If it is only too far ahead of the chain head, retrying later may be possibleIf expiration is earlier than the next eligible block time, the transaction cannot become valid again and must be rebuilt. If this was its first and only submission and the node explicitly returned this error, it can be rebuilt immediately. If expiration exceeds the node's permitted future window of approximately 24 hours, wait for the head to advance and then rebroadcast the same signed transaction, provided its TAPOS reference remains valid. If an earlier submission may have occurred or its outcome is unknown, follow the safe rebroadcast and replacement procedure before creating a replacement
Validation balance not sufficientYes, provided the transaction's expiration and TAPOS reference remain validAfter adding sufficient funds, rebroadcast the exact same signed transaction; do not rebuild it. If the original node returns DUP_TRANSACTION_ERROR because of the optional RPC transaction cache, rebroadcast through another reliable, synchronized node and continue tracking the original txID
Execution REVERT / OUT_OF_ENERGY / OUT_OF_TIMENoDiagnose from the receipt and exact error message. For OUT_OF_ENERGY, check fee_limit; for OUT_OF_TIME, use the exact error message to determine whether execution timed out or a protocol check triggered the result. Correct the cause, then build a new transaction

Idempotency

Two safety properties to know:

  • Re-broadcasting the same signed transaction is harmless. The exact signed payload retains the same txID, and network deduplication prevents it from executing twice. A node that detects it may return DUP_TRANSACTION_ERROR. Use this property during retries: after a timeout or 5xx response, rebroadcast the same payload rather than creating a replacement.
  • A broadcast call that reports no error does not mean that the transaction succeeded. A result: true response means only that the broadcast call returned no error. Keep the original txID and query solidified results: use /walletsolidity/gettransactionbyid for a direct TRX or TRC-10 transfer, and also query /walletsolidity/gettransactioninfobyid for a smart-contract transaction. See Confirmation semantics for endpoint selection and response meanings.

Do not create a replacement immediately for a transaction that was broadcast or whose broadcast outcome is unknown. Follow the safe rebroadcast and replacement procedure and check the original txID against a data source that can provide every solidified block in the transaction's entire possible inclusion interval. Rebuild only after the latest solidified block timestamp reaches the original raw_data.expiration and none of the relevant blocks contains the original transaction. A local clock later than raw_data.expiration, a request timeout, or a single empty {} response from /walletsolidity/gettransactionbyid does not prove that the transaction was never included.


Debugging endpoints

EndpointUse
/wallet/triggerconstantcontractEstimate Energy for a contract call without broadcasting; surfaces revert reasons before paying for execution
/wallet/estimateenergyEnergy estimation (java-tron 4.7.0.1+); more precise than triggerconstantcontract for cost prediction
/walletsolidity/gettransactioninfobyidInspect execution information from solidified data; use /walletsolidity/gettransactionbyid to test whether the transaction body exists
/wallet/gettransactioninfobyidSame as above but reads from head; available sooner but subject to reorg
/walletsolidity/getblockbynumWalk a specific block's transactions when debugging deposit detection
/wallet/getaccountresourceCheck the sender's Bandwidth, Energy, and fee_limit budget before a large transaction
/wallet/getchainparametersQuery current values of dynamic parameters (e.g., getUnfreezeDelayDays, getEnergyFee) when a transaction fails for parameter-based reasons

For smart-contract development, simulate calls with triggerconstantcontract before committing real transactions. The endpoint itself does not require a transaction-level fee_limit; convert the returned energy_used with the current getEnergyFee and compare it with the fee_limit planned for the real transaction.


Related resources

  • API workflow — what each step in the lifecycle can fail at
  • Encoding — encoding mistakes are the most common validation-error source
  • Resource model — Bandwidth, Energy, fee_limit
  • Smart contract errors — use the exact error message to determine whether OUT_OF_TIME was triggered by an execution timeout or a protocol check
  • FAQ — community-curated answers to common errors