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:
| Code | Cause | Fix |
|---|---|---|
SIGERROR | Signature verification failed | Verify the private key used to sign matches the address sending the transaction; check the key's hex format. |
BANDWITH_ERROR | Insufficient Bandwidth before broadcast, or insufficient TRX to pay for Bandwidth, new-account creation, multisig, or memo fees; this does not indicate TVM Energy exhaustion | Query /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_ERROR | The 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 matched | Query 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_ERROR | The referenced TAPOS block number and hash do not match a recent block known to the node | Rebuild using a recent block recognized by the synchronized node. The latest solidified block is usually a more conservative choice. |
TOO_BIG_TRANSACTION_ERROR | Transaction byte size exceeds the limit (typically caused by an oversized memo) | Reduce the size of the transaction. |
TRANSACTION_EXPIRATION_ERROR | The 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_BUSY | The whole network is busy, or this node's pending pool is overflowing | See SERVER_BUSY below. |
NOT_ENOUGH_EFFECTIVE_CONNECTION | This node has not synced to the latest block | Compare wallet/getnowblock against TronScan's current block height; if behind, wait for sync to catch up or switch to a fully-synced node. |
OTHER_ERROR | Unknown error | Inspect the node log for detail. |
NO_CONNECTION | The node has no available P2P connections | Configure a seed.node and restart the node. |
CONTRACT_EXE_ERROR | Contract execution failed during pre-execution due to a runtime or illegal-protobuf exception | Inspect the node log for detail. |
BLOCK_UNSOLIDIFIED | The 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_ERROR | Pre-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
CONTRACT_VALIDATE_ERROR messagesThe error code only means "validation failed"; the real reason is in message, hex-encoded. Common decoded messages:
| Decoded message | Cause |
|---|---|
account does not exist | The signing or recipient address has never been activated on-chain. Send it a small TRX amount first. |
Validate ... error, no OwnerAccount | The owner_address in the request is malformed or unknown. |
No contract or not a valid smart contract | The contract address in the request is wrong or points to a non-contract account. |
this node does not support constant | The 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:
-
Always send the API key in the
TRON-PRO-API-KEYheader. Requests without a key are aggressively rate-limited or rejected outright. Header format and request handling are documented in TronGrid rate limits. -
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.
-
Respect
Retry-Afterheaders when present. See Errors and debugging — retry strategy. -
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:
-
Wait out the expiration window. The transaction expires 60 seconds after construction (
TRANSACTION_DEFAULT_EXPIRATION_TIMEinConstant.java). After that point you can be sure it will not land. -
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. -
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
- Errors and debugging — error categories, hex decode procedure, retry strategy
- API workflow — construct, sign, broadcast lifecycle
- Confirmation semantics — distinguish broadcast acceptance, receipt availability, and solidified final state
- Smart contract errors — on-chain execution failures (REVERT, OUT_OF_ENERGY, OUT_OF_TIME)
- Node operations issues — node-side sync and stability problems
- FAQ — Q&A hub
Updated 7 days ago