UltraSend Errors and Retries
Handle UltraSend rejection, timeout, duplicate, balance, and service failure states without double-sending or rebuilding transactions.
Retry decisions depend on whether the server returned a definite response or the network result was ambiguous.
Ambiguous timeout rule
If the client times out before receiving an HTTP or QUIC receipt, the relay may already be processing the signature. Retry the same serialized bytes. Do not fetch a new blockhash, rebuild, or resign until the original transaction is known to have expired.
serialize and sign once | vsubmit exact bytes ---- definite rejection ----> fix or stop | +---------- accepted receipt ----------> confirm with RPC | +---------- ambiguous timeout ---------> retry exact bytesUltraSend deduplicates by customer and transaction signature for a bounded window. Your application should also retain the signature and serialized payload until the send attempt reaches a terminal state.
Backoff
Use short bounded backoff only for ambiguous transport errors, 409, and recoverable 503 responses. A practical starting schedule is 100 ms, 250 ms, 500 ms, and 1 second, capped by the transaction blockhash lifetime and your own execution deadline.
Do not run an unbounded retry loop. When the blockhash expires, create and sign a new transaction as a new submission attempt.
Billing outcomes
- Invalid or unauthorized: not charged.
- Insufficient balance: not charged.
- Duplicate or already in progress: no second charge.
- Forwarding failure: charge reversed.
- Accepted but never observed on-chain: charged.
- Accepted and finalized with a chain error: charged.
Return to the complete implementation guide.