TriportRPC

Why an EVM transaction is stuck: nonce gaps

Last updated:

At a glance

Symptom details
PropertyValue
SymptomHash returned, receipt stays null, no error
Ordering ruleOne sender's transactions are mined strictly in nonce order
Pool state of the stuck transactionqueued — nonce higher than the next executable one
Next expected nonceeth_getTransactionCount(sender, "latest")
Replacement rule (Geth default)Same nonce with a fee at least 10% higher (--txpool.pricebump)

What you see

eth_sendRawTransaction accepted your transaction and returned a hash, but it never gets mined: eth_getTransactionReceipt stays null and later transactions from the same account pile up behind it. Nothing ever reports an error.

Why this happens

Each account has a nonce: the number of transactions it has already had mined. The next transaction must carry exactly that nonce. A node's transaction pool keeps two groups: pending transactions, which are executable now because their nonce is the next one (or follows a pending one), and queued transactions, whose nonce is higher than that — they depend on a transaction the pool does not have. A gap appears when a transaction with a lower nonce was never broadcast, was dropped as underpriced, or was sent to a different node; when two processes sign for the same account and each keeps its own counter; or when a client computes the next nonce from eth_getTransactionCount with the "latest" tag while earlier transactions are still pending. Every later transaction from the account is blocked until the gap is filled. Nodes do not keep queued transactions forever either — Geth, for example, limits how long non-executable transactions stay queued (--txpool.lifetime, default three hours) — so a stuck transaction can silently disappear.

What to do

  1. Compare eth_getTransactionCount(sender, "latest") — the next nonce the chain expects — with the nonce of your stuck transaction. If yours is higher, the missing nonces in between are the gap.
  2. Use eth_getTransactionCount(sender, "pending") to see what the node thinks the next nonce is including its own pending pool; if it is lower than your transaction's nonce, the node does not have the missing ones either.
  3. Fill the gap: send a transaction for each missing nonce (a zero-value self-transfer works). Once the lowest nonce is mined, the queued transactions become executable in order.
  4. To replace a transaction instead, resend the same nonce with a higher fee. Nodes require a minimum bump before they accept a replacement (Geth's default --txpool.pricebump is 10%).
  5. Prevent recurrence by assigning nonces from one place per account, and by tracking the pending count rather than the latest count when sending several transactions in a row.

When this is not our problem

Nonce ordering is enforced by the EVM protocol and by every node's transaction pool, not by the RPC provider: the same gap blocks the same account on any provider, Triport included. The only fix is on the signing side — send the missing nonce or replace the transaction.

FAQ

What is the difference between pending and queued transactions?
Pending transactions can be mined now because their nonce is next in line. Queued transactions have a higher nonce and wait for the missing lower nonces; they are never mined while the gap exists.
Will a stuck transaction eventually go through on its own?
Only if the missing lower-nonce transactions arrive. Otherwise it stays queued until the node evicts it, which is why the gap has to be filled from the signing side.

Sources