Broadcast and RPC errors

How TRON nodes report broadcast failures and rate-limited RPC responses — the full response-code table, the SERVER_BUSY pending-pool overflow, the TronGrid 503 rate-limit response, and what to do when a successful broadcast never appears on chain.

📘

Prerequisites

This page is the reference for errors returned by the node when you broadcast a transaction, and for rate-limited responses from hosted RPC gateways. Errors that happen after the transaction is included in a block (on-chain execution failures like REVERT / OUT_OF_ENERGY / OUT_OF_TIME) are covered in Smart contract errors; the diagnostic categories and decoded message format are in Errors and debugging.


Broadcast response codes

A wallet/broadcasttransaction call returns a top-level code field on failure. The full set of codes the node may return:

CodeCauseFix
SIGERRORSignature verification failedVerify the private key used to sign matches the address sending the transaction; check the key's hex format.
BANDWITH_ERRORInsufficient Bandwidth before broadcast, or insufficient TRX to pay for Bandwidth, new-account creation, multisig, or memo fees; this does not indicate TVM Energy exhaustionQuery /wallet/getaccountresource and /wallet/getchainparameters, identify whether the transaction creates an account or includes multiple signatures or a memo, then add Bandwidth or TRX as needed.
DUP_TRANSACTION_ERRORThe same txID is usually already in the current node's Pending Pool or a block. If node.rpc.trxCacheEnable is enabled, only the RPC broadcast cache may have matchedQuery the original transaction and receipt by txID. Regardless of the RPC cache setting, this error does not prove that the transaction is on-chain. While it remains valid, rebroadcast the same signed transaction to another reliable synchronized node. Rebuild only after it expires and is confirmed not to be on-chain, to avoid duplicate payment.
TAPOS_ERRORThe referenced TAPOS block number and hash do not match a recent block known to the nodeRebuild using a recent block recognized by the synchronized node. The latest solidified block is usually a more conservative choice.
TOO_BIG_TRANSACTION_ERRORTransaction byte size exceeds the limit (typically caused by an oversized memo)Reduce the size of the transaction.
TRANSACTION_EXPIRATION_ERRORThe transaction expired before reaching the mempool. Default expiration is 60 seconds (TRANSACTION_DEFAULT_EXPIRATION_TIME in Constant.java)Broadcast the transaction before expiration. For node-built transactions, increase trx.expiration.timeInMilliseconds in your local config. For public-node APIs, the 60-second window cannot be extended. For locally-constructed transactions, set a longer expiration.
SERVER_BUSYThe whole network is busy, or this node's pending pool is overflowingSee SERVER_BUSY below.
NOT_ENOUGH_EFFECTIVE_CONNECTIONThis node has not synced to the latest blockCompare wallet/getnowblock against TronScan's current block height; if behind, wait for sync to catch up or switch to a fully-synced node.
OTHER_ERRORUnknown errorInspect the node log for detail.
NO_CONNECTIONThe node has no available P2P connectionsConfigure a seed.node and restart the node.
CONTRACT_EXE_ERRORContract execution failed during pre-execution due to a runtime or illegal-protobuf exceptionInspect the node log for detail.
BLOCK_UNSOLIDIFIEDThe node has too many unsolidified blocks (exceeds node.maxUnsolidifiedBlocks)Wait for the node to recover. For self-hosted nodes, you can disable the check with node.unsolidifiedBlockCheck, or raise the threshold via node.maxUnsolidifiedBlocks.
CONTRACT_VALIDATE_ERRORPre-execution validation failed (system-contract validation)The actual cause is in the message field, hex-encoded. Decode with a hex-to-string tool. See CONTRACT_VALIDATE_ERROR messages below.

CONTRACT_VALIDATE_ERROR messages

The error code only means "validation failed"; the real reason is in message, hex-encoded. Common decoded messages:

Decoded messageCause
account does not existThe signing or recipient address has never been activated on-chain. Send it a small TRX amount first.
Validate ... error, no OwnerAccountThe owner_address in the request is malformed or unknown.
No contract or not a valid smart contractThe contract address in the request is wrong or points to a non-contract account.
this node does not support constantThe node's vm.supportConstant is set to false. Common on self-built nodes — see Exchange wallet integration for required VM config keys.

For the full hex-decode procedure and the rest of the error-category taxonomy, see Errors and debugging.


SERVER_BUSY — pending-pool overflow

If the node's number of unprocessed transactions exceeds 2,000, broadcast returns SERVER_BUSY.

Fix (self-hosted nodes): raise the pending-pool size in config.conf:

node.maxTransactionPendingSize = 5000

Adjust the value to your hardware capacity. Hosted services (TronGrid) tune this themselves; if you see SERVER_BUSY against TronGrid, you are hitting a global capacity event rather than a per-node setting — retry with backoff or switch endpoints.


TronGrid 503 service temporarily unavailable

TronGrid enforces per-IP rate limits across all requests. When your access frequency exceeds the limit, TronGrid returns 4xx / 5xx error codes (most commonly HTTP 503).

Fix:

  1. Always send the API key in the TRON-PRO-API-KEY header. Requests without a key are aggressively rate-limited or rejected outright. Header format and request handling are documented in TronGrid rate limits.

  2. Reduce request frequency. Limit the burst at DApp start-up; do not poll TronGrid faster than the chain produces blocks — a 3-second slot makes faster-than-3-second polling pointless.

  3. Respect Retry-After headers when present. See Errors and debugging — retry strategy.

  4. For production volume, consider a customized TronGrid tier (submit a configuration request through the TronGrid console — limits like QPS and total rate are tuned per API key) or running your own full node. See RPC and indexer providers for the comparison.

For the full rate-limit policy, see TronGrid rate limits.


Broadcast succeeded but the transaction never appears on chain

wallet/broadcasttransaction returned {"result": true}, but gettransactioninfobyid continues to return empty after several block intervals.

Cause: the node accepted the transaction into its local mempool, but the transaction never propagated to a producing SR — usually because of network instability between the broadcasting node and the SR fleet, or because the broadcasting node itself is partitioned.

Fix:

  1. Wait out the expiration window. The transaction expires 60 seconds after construction (TRANSACTION_DEFAULT_EXPIRATION_TIME in Constant.java). After that point you can be sure it will not land.

  2. Rebroadcast within the window. Submit the same signed transaction to a different node — the network deduplicates by txID, so a duplicate broadcast returns the same hash and is harmless. If a fully-synced node accepts and propagates it, you may still get inclusion.

  3. After expiration, rebuild and resign. Reconstruct a fresh transaction from a current TAPOS reference, sign, and broadcast. Do not reuse the old txID — once expired, the same payload is dead.

The safety property to internalize: a successful broadcast confirms mempool acceptance, not block inclusion. Always confirm via walletsolidity/gettransactioninfobyid before treating the operation as final. See Errors and debugging — idempotency.


Related resources