TRANSACTION LIFECYCLE — Solana × Banking Stage

Why Your Solana Transaction Vanished Without an Error

8 min read
SolanaTransactionsQUICDebugging

The worst outcome on Solana is not a failed transaction. A failed transaction tells you what went wrong: the log says slippage, or insufficient funds, or a program error, and you fix it. The worst outcome is the one where you sign, the wallet says "sent", and a minute later the signature does not exist. No error, no log, no fee charged, no explanation.

That silence has causes. There are seven places in the validator where a transaction is discarded without any record reaching you, and each one is a specific rule with a specific number. Knowing which door closed does not bring the transaction back, but it tells you what to change so the next one gets through.


Door One: The Leader's Floor, Closed Before Your Signature Is Checked

A leader buffers up to 100,000 transactions. When that buffer reaches 99% full, the scheduler publishes a floor — the priority of the lowest transaction it still holds — and the signature-verification stage discards any incoming packet below it before verifying it. The floor lifts only when the buffer drains back to 95%.

Below the floor your transaction never existed as far as that leader is concerned. Votes are exempt; everything else is not. And "priority" here is not your fee, it is your fee divided by the block space you requested — a transaction with a default 1.4-million-unit compute limit sits far lower than its fee suggests. Right-sizing that limit is the cheapest way through this door.


Door Two: The Two-Second Memory That Eats Your Resend

Every packet that reaches a validator is hashed into a bloom filter of 63,999,979 bits. If the same bytes arrive again within 2 seconds, the second copy is dropped as a duplicate. The filter resets when it ages past two seconds or when its false-positive rate reaches 0.1%.

Two consequences. Resending the identical signed transaction within two seconds achieves nothing; the copy is discarded. And roughly one in a thousand honest, distinct transactions is dropped as a false duplicate, with no counter you can see. If you resend, resend after two seconds — or resend as a new transaction with a fresh blockhash.


Door Three: The Connection Your RPC Does Not Have

Leaders accept transactions over QUIC, and they allocate capacity by the stake of the sender. A connection from an unstaked sender gets 128 concurrent streams. A staked sender's allowance scales with its share of stake, saturating at 512. A validator whose stake is below one fifty-thousandth of the total is treated as unstaked.

Your wallet never talks to the leader; your RPC provider does. If the provider forwards through an unstaked node, your transaction is competing for one of the smallest lanes at the door, and under load the lane is full. Nothing tells you this. The transaction is simply not admitted, and the provider's retry loop tries again into the same full lane.


Door Four: Forwarding Only Goes One Hop, and Only for the Staked

If a node that is not the leader receives your transaction, it may forward it to the upcoming leaders — but only if the packet came from a staked node, and never a packet that was itself forwarded. Forwarding targets the leaders at 2, 6 and 10 slots ahead, and is capped at 12 MB per second per node.

On the receiving side, a leader's fetch stage discards forwarded packets unless it is due to lead within 20 slots, about 8 seconds. A forwarded transaction that arrives at a validator whose window is 30 slots away is dropped on arrival.


Door Five: The Retry Service's Limits

When you send through an RPC node, it keeps your transaction in a retry pool and rebroadcasts every 2 seconds to the next 2 leaders. The pool holds 10,000 transactions; beyond that, a new transaction is sent once and then forgotten. A transaction that landed but failed on chain is dropped from the pool immediately and never retried. One that landed but has not been rooted is retained, so it can be resent if its fork dies.

Two settings decide your fate here. maxRetries: 0 means exactly one broadcast, no retries. And the node's idea of who the leader is refreshes every 1,000 ms — two and a half slots — so under a fast leader rotation it can be aiming at the previous leader for a quarter of every window.


Door Six: The Leader That Cannot Be Reached in Time

Direct-to-leader senders open QUIC connections to the next few leaders ahead of time. If a leader does not complete the handshake within 2 seconds, the sender sleeps another 1.6 seconds before retrying — by which time that leader's four-slot window, 1.6 seconds long, is over. One unreachable leader costs you its entire window.

The address book is stale too. The list of validator addresses is refreshed every 5 minutes in the widely used client; a validator that restarts on new ports is unreachable to almost every sender for up to five minutes, and validators that do not advertise a QUIC port are skipped entirely as probably delinquent.


Door Seven: The Block Is Full in a Way You Cannot See

A block has four independent ceilings: 60 million compute units in total, 24 million per writable account, 100 MB of new account data, and 20 MiB of entries. A transaction that would breach any of them is not failed — it is held until the next block. Then the next. On a hot pool that has already absorbed its 24 million units, every transaction writing to it waits, while its blockhash ages.

After 150 slots — about a minute — the blockhash expires and the transaction can never land. The node stops retrying, the status query returns null, and the transaction has vanished, having never been invalid for a single moment.


How to Tell Which Door It Was

There is no report. You infer.

  • Status null after a minute, blockhash expired. It never landed. Rule out the fee first — compute your rank, not your price — then the account: if the pool you wrote to shows a high floor in the last 150 slots, it was contention, and the fix is timing and a smaller compute reservation, not a bigger tip.
  • Status null immediately after a resend. You hit the two-second filter. Wait, or rebuild with a new blockhash.
  • Landed on simulation, vanished in practice, repeatedly, on one provider. Ask what stake sits behind their sending node. The lane at the leader's door is theirs, not yours.
  • Everything landed except during one leader's window. That leader was unreachable or rotating; the retry service aimed at the wrong node for part of the window. Nothing you did caused it, and nothing but the next window fixes it.

And if the transaction cannot afford to expire at all — a payout, a signed approval, anything with a human in the loop — the blockhash is the wrong tool. A durable nonce replaces it with one that lasts until you choose, which is its own post and its own set of hazards.


Dropped Transactions: Questions People Actually Ask

Why does my Solana transaction disappear with no error?

Because it was discarded before execution. The leader’s priority floor, a 2-second duplicate filter, stake-weighted admission, forwarding rules, retry-pool limits and block ceilings all drop transactions silently, and a transaction that never executes leaves no log.

How long does a Solana transaction stay valid?

150 slots after its blockhash, about one minute at 400 ms slots. If it has not landed by then it can never land, and the signature status stays null.

Does resending the same Solana transaction help?

Not within two seconds; an identical packet is dropped as a duplicate. After that, resending helps only if the cause was reachability. If the cause was the fee floor or a full account, rebuild with a smaller compute limit or wait for the account to clear.

Is skipPreflight the reason my transaction vanished?

Skipping preflight removes the simulation that would have told you about an on-chain error, so a transaction that would fail is broadcast anyway. It does not by itself cause a drop, but it removes the only warning you had.

Constants read from the Agave validator source at commit beee69b958: core/src/banking_stage, core/src/sigverify_stage.rs, streamer/src/nonblocking/swqos.rs, send-transaction-service and cost-model/src/block_cost_limits.rs. Every one of these numbers changes with releases — re-read them before you depend on one.

xroot.devOn-chain research, published in full
𝕏 @xrootdev
← Back to all notes