Skip to content
Guides5 min read

TRON Energy Rental API Limits and Error Codes: What Your Integration Must Handle

Oliver BentleyTRON Research Editor

You won't be handling one set of responses but three levels. The first is the HTTP API of the rental service itself: request rate, daily quota, key binding, plus its own order error codes (insufficient balance, invalid address, energy amount too small). The second is the node or TronGrid through which the delegation transaction is sent. The third is the TRON blockchain: broadcast errors and TVM execution errors. A retry that makes sense on one level will cause double payment on another, so parse responses by class rather than by message text.

Level 1: HTTP API limits

Quotas are set by the service itself: requests per second per key, daily order count, minimum lot. The exact numbers come from its documentation, but the order error classes are the same everywhere:

  • Insufficient balance (INSUFFICIENT_BALANCE and equivalents) — retrying is pointless, you need to top up the TRX deposit; watch the threshold in advance, otherwise delivery stalls right at the peak of USDT TRC-20 transfers.
  • Invalid recipient address — usually hex instead of base58, or a broken checksum. Validate the format (T…, 34 characters) before ordering: energy is delegated to the address you specify, and the mistake can't be undone.
  • Amount or duration too small — services have a minimum lot, often around 32,000 energy, roughly one USDT TRC-20 transfer to an address with a non-zero balance; round your calculated amount up to the lot size.

The node that broadcasts the delegation produces the same classes: TronGrid answers a rate limit breach with 429, 403, or 503, and the body differs — the V1 API returns "success": false and "statusCode": 429, the node's HTTP proxy returns only an Error field, and the per-IP limit arrives with a Retry-After header. The documentation is explicit: you must not detect a limit from error text — look at the HTTP status, the body fields, and whether a key was passed.

  • 429/503 — exponential backoff with jitter. Without jitter, several instances retry in sync and hit the limit again.
  • 403 — don't hammer it with retries: first check the key, the security settings, and a possible temporary block.
  • Cache read methods. Account state, network parameters, and block statistics don't need millisecond freshness: a TRON block appears roughly every 3 seconds, so polling more often is usually pointless.

Level 2: broadcast error codes

Energy delegation is an ordinary TRON transaction, so it gets the same set of responses as any other.

CodeCauseWhat to do
SIGERRORsignature failed validationverify the private key against the sender address and check the key's hex format; do not retry
BANDWITH_ERRORnot enough Bandwidth or TRX for bytes, account creation, multisig, memothis is not Energy exhaustion; check /wallet/getaccountresource, add Bandwidth or TRX
DUP_TRANSACTION_ERRORthe same txID is already in the pending pool, in a block, or in the node's RPC cachedon't rebuild it; re-broadcast the same signed transaction to another synchronized node
TAPOS_ERRORthe TAPOS block number and hash didn't match a recent blockrebuild against a fresh block, or more safely against the latest solidified one
TRANSACTION_EXPIRATION_ERRORthe lifetime expired (60 seconds by default)rebuild and sign again; the window can't be extended on public APIs
SERVER_BUSYthe node's pending pool is full (node.maxTransactionPendingSize, 2000 by default)retry with backoff or switch endpoints
NOT_ENOUGH_EFFECTIVE_CONNECTIONtoo few effective P2P peers, or the transaction wasn't relayed to anyoneretry through another healthy endpoint

The main trap is DUP_TRANSACTION_ERROR: it does not prove the transaction made it onto the blockchain. The rule: a transaction may only be rebuilt after its expiration has passed and you have confirmed it is not in the chain — otherwise it's easy to pay twice.

Level 3: energy errors and fee_limit

These errors relate to execution and occur after the transaction is already included in a block.

  • OUT_OF_ENERGY — execution consumed all the energy allowed by fee_limit; the energy spent is not refunded. Re-estimate consumption, raise fee_limit, and check the contract's consume_user_resource_percent.
  • OUT_OF_TIME — the transaction's CPU budget was exceeded (chain parameter #13 getMaxCpuTimeOfOneTx, currently 80 ms on Mainnet).

Two fee_limit mistakes show up in integrations constantly. The first is a value in TRX instead of sun: fee_limit = 100 authorizes 0.0001 TRX, and the call fails immediately with OUT_OF_ENERGY. The second is believing the limit is charged in full: it's a ceiling, and on normal execution — and on REVERT — only the energy actually used is charged. The node checks the condition 0 ≤ fee_limit ≤ MaxFeeLimit and returns ContractValidateException if it's exceeded — the transaction never reaches the VM and no energy is spent (details).

Don't hardcode the values: the fee_limit maximum (parameter #47, currently 15,000 TRX) and the energy price (getEnergyFee, currently 100 sun) are chain parameters changed by SR voting, and they are read via wallet/getchainparameters. The same goes for the dynamic model: with getAllowDynamicEnergy enabled, the multiplier for popular contracts reaches 3.4, and an amount rented "exactly per the estimate" may fall short (resource payment model).

What to build into the integration

  1. Estimate before ordering. wallet/triggerconstantcontract returns energy_used, wallet/estimateenergy returns energy_required (not available on all public RPCs). Add a buffer to the estimate for the dynamic multiplier.
  2. An idempotency key for every order. A timeout or a 5xx doesn't mean the order wasn't created: repeat the request with the same key.
  3. Classify responses in code: "limit" — backoff, "credentials" — alert with no retries, "state/network" — retry under the idempotency key, "business error" — log it and send it for manual review.
  4. Confirm by fact, not by HTTP 200. Cross-check the delivery webhook against wallet/getaccountresource for the target address, and keep a backup endpoint: SERVER_BUSY, NOT_ENOUGH_EFFECTIVE_CONNECTION, and rate limiting are all cured by switching nodes, provided you planned for it.

Numeric boundaries — quotas, energy price, the fee_limit maximum, the CPU limit — should be read from the network and from the specific service's documentation, not from constants in your code: they change, and an energy delivery pipeline breaks silently.

Read next

Guides
How to combine webhooks and polling to reliably confirm energy delivery on TRON: finality levels, GetDelegatedResourceV2, idempotency and endpoint protection.
Oliver Bentley · 4 min read
Guides
How TRX perpetual futures work, how a cash-settled contract on Moscow Exchange crypto indices differs from buying the coin, and what it means for TRON in Russia.
Oliver Bentley · 3 min read