Broadcast and RPC errors
How TRON nodes report broadcast failures and rate-limited RPC responses — the full response-code table, the SERVER_BUSY cached-transaction limit, the TronGrid 503 rate-limit response, and how to retry safely when a transaction cannot be found after broadcast.
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 | This error does not prove that the transaction is on-chain. While it remains valid, rebroadcast only the exact signed transaction to the original node or another reliable, synchronized node. Its txID remains unchanged, so it cannot create a second execution. Before creating a replacement, check the original txID using the procedure below. |
TAPOS_ERROR | The referenced TAPOS block number and hash do not match a recent block known to the node | If this was the transaction's first and only submission, rebuild it using a recent block recognized by the synchronized node; the latest solidified block is usually a more conservative reference. If an earlier submission may have occurred or its outcome is unknown, preserve the original txID and complete the solidified-history procedure before creating a replacement. |
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 raw_data.expiration value is outside the node's valid range: earlier than the next available block slot or more than approximately 24 hours after the chain head. Node-built transactions use a default validity interval of about 60 seconds | Minimize the delay between construction, signing, and broadcast, and keep expiration within the protocol bounds. Self-hosted nodes can adjust trx.expiration.timeInMilliseconds; locally constructed transactions can set a valid expiration. Changing raw_data changes the txID and requires a new signature. If the same transaction may have been submitted earlier, check its original txID using the safe rebroadcast and replacement procedure below. |
SERVER_BUSY | The current node's cached transaction count exceeds node.maxTransactionPendingSize | See SERVER_BUSY below. |
NOT_ENOUGH_EFFECTIVE_CONNECTION | The node has fewer effective P2P peers than minEffectiveConnection, or it could not broadcast the transaction to any peer | Check the node's peer count and synchronization state. Because this code can be returned after the transaction enters the local Pending Pool, preserve the original txID and treat the outcome as unknown. While the transaction remains valid, rebroadcast only the exact same signed payload through a reliable, synchronized endpoint. Before creating any replacement, use the solidified-history procedure below. |
OTHER_ERROR | Unknown error | Inspect the node log, preserve the original txID, and treat the outcome as unknown. Continue querying the original transaction and, while it remains valid, rebroadcast only the exact same signed payload. Before creating any replacement, use the solidified-history procedure below. |
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 | When node.unsolidifiedBlockCheck is enabled, the number of unsolidified blocks has reached or exceeded node.maxUnsolidifiedBlocks | Wait for the node to recover and inspect its synchronization and P2P status. If adjustment is necessary, assess the operational risk before increasing node.maxUnsolidifiedBlocks or disabling the check with node.unsolidifiedBlockCheck; restart FullNode after changing either setting. |
CONTRACT_VALIDATE_ERROR | Pre-execution validation failed (system-contract validation) | The actual cause is in message. It is normally hex when visible is omitted or false, but may be UTF-8 text when visible: true; detect the format before decoding. 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. Decode it only when the returned value is an even-length hex string. Common plain-text messages are:
| 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 — cached-transaction limit exceeded
Broadcast requests return SERVER_BUSY when the current node's cached transaction count exceeds the limit configured by node.maxTransactionPendingSize. The default limit is 2000.
Fix (self-hosted nodes): raise the limit in config.conf according to the node's available memory and CPU capacity:
node.maxTransactionPendingSize = 5000Restart FullNode after changing the setting. Hosted services such as TronGrid manage this setting themselves. A SERVER_BUSY response from TronGrid means that the backend node handling the request cannot accept additional transactions at that time; it does not establish a network-wide condition. 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.
How should I retry when a transaction cannot be found after broadcast?
A broadcast request may return {"result": true, "txid": "..."}, or it may time out without a conclusive response. If subsequent queries do not return the original transaction, its status remains unknown. Preserve the original txID and do not immediately create a new transaction.
result: true means only that the node handling the broadcast request did not report an error. It does not prove that the transaction was included in a block, executed successfully, or solidified. If the request timed out, you also cannot tell whether the node accepted the transaction.
An empty {} response from /walletsolidity/gettransactionbyid means only that this query did not return the original transaction from the solidified chain. Until the latest solidified block timestamp and historical query coverage have been verified, none of the following proves that the original transaction was not included in the solidified chain: the local system time has passed raw_data.expiration, a request timed out, or one query returned an empty response.
When the original transaction cannot be found after broadcast, use the following process to determine whether it entered the solidified chain:
-
Rebroadcast only the original transaction. Preserve the original
txIDand signed transaction. While the checks below are in progress, if you need to rebroadcast, submit the exact same signed transaction to a reliable, synchronized node. The node still applies normal transaction validation, so rebroadcasting does not guarantee acceptance. Rebroadcasting does not change thetxID. A node may returnDUP_TRANSACTION_ERROR, but that response does not prove that the transaction is on-chain. -
Determine the start block.
- If the application recorded the latest solidified block immediately before the first broadcast, use that block as the start block.
- If only send logs are available, and they cover every broadcast attempt and the system clock was synchronized, use the last solidified block whose timestamp is earlier than the earliest send time as the start block. The client supplies
raw_data.timestamp, so it is not a substitute for the actual send time. - If neither source of information is available, subtract 24 hours from
raw_data.expiration, find the first solidified block whose timestamp reaches or exceeds that time, and use the following block as the start block. When accepting a transaction or validating a transaction in a block, java-tron rejects it if itsexpirationis more than 24 hours after the current head-block time. During block validation, the head block is the block preceding the one being validated. Therefore, the first block at or after the calculated time cannot itself have included the original transaction; the following block is the earliest one in which it could have been included.
-
Select a query source and confirm query coverage. Choose a reliable, synchronized node or RPC service that provides both
/walletsolidity/getnowblockand/walletsolidity/gettransactionbyid. First, use the source's data-retention configuration or its documented historical-query coverage to confirm that/walletsolidity/gettransactionbyidcan retrieve transactions included in the start block and subsequent solidified blocks. If this cannot be confirmed, switch query sources. After selecting a suitable source, call/walletsolidity/getnowblockuntilblock_header.raw_data.timestampin the returned block reaches or exceeds the originalraw_data.expiration, and use that block as the end block. At that point, every block in which the original transaction could have been included has been solidified, and query coverage extends from the start block through the end block. -
Look up the original transaction and decide what to do next. Query
/walletsolidity/gettransactionbyidon the selected source using the originaltxID:- If the transaction is returned, it has entered the solidified chain. Do not create a new transaction under the assumption that the original one was not included. For a smart contract transaction, inclusion in the solidified chain does not mean successful execution. To inspect the complete execution result, resource usage, and other details, use
/walletsolidity/gettransactioninfobyidto retrieve the solidified transaction information. If the selected source cannot return that information, use one that can. - If the endpoint returns an empty
{}response, step 3 has established that every block in which the original transaction could have been included is solidified and that the selected source provides complete query coverage. You can therefore conclude that the original transaction was not included in the solidified chain. Only then should you rebuild, sign, and broadcast a new transaction.
- If the transaction is returned, it has entered the solidified chain. Do not create a new transaction under the assumption that the original one was not included. For a smart contract transaction, inclusion in the solidified chain does not mean successful execution. To inspect the complete execution result, resource usage, and other details, use
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 the broadcast response, 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 about 20 hours ago