A transaction has landed when a leader has included it in a block, which is a separate event from your client sending it successfully. Between those two events sit a forwarding path, a queue at the validator, a fee market for contended accounts and a hard validity deadline. Transactions lost in that gap leave no on-chain trace at all, which is why they are so often mistaken for bad luck.
What landed actually means
Four different things get called success, and conflating them is the root of most confusion in this area.
- Submitted
- Your RPC endpoint accepted the transaction and returned a signature. This proves the request was well formed. It proves nothing about inclusion.
- Processed
- A leader executed the transaction in a block. The block might still be abandoned if the cluster does not build on it.
- Confirmed
- A supermajority of validators has voted on the block containing it. For trading purposes this is the practical decision point.
- Finalized
- The block is rooted and will not be reverted. Safest, slowest, and usually unnecessary for intra-session position tracking.
The distinction that matters operationally is between submitted and processed. A signature returned by sendTransaction is a receipt for a request, not evidence of execution. Any dashboard that counts returned signatures as trades is counting intentions. If a tool cannot show you what fraction of its intentions became blocks, it is not measuring its own execution.
There is one useful asymmetry here. A transaction that lands and then fails on chain, for example because slippage was exceeded, still pays its fee and still leaves a record you can inspect. A transaction that never lands pays nothing and leaves nothing. The first is an expensive but debuggable event; the second is free and invisible, which is exactly why it goes unmeasured.
The path a transaction takes
Solana does not hold pending transactions in a shared public pool. Clients hand them to an RPC node, which forwards them over QUIC to the validator scheduled to lead the current slot and to the leaders scheduled shortly after. Because the leader schedule for an epoch is deterministic, this forwarding is targeted rather than broadcast.
Three properties of that path explain most drops:
- Leaders rotate in short turns. A leader produces blocks for a run of consecutive slots and then hands over. A transaction that arrives just as the handover happens can miss both the outgoing and incoming leader's processing window.
- Ingress is a contended resource. Validators accept connections under limits, and bandwidth is allocated in a stake-weighted manner. Traffic arriving through a provider with stake-weighted access is treated differently from traffic arriving from an anonymous connection during a burst.
- Nothing is obliged to queue your transaction. If a validator's ingress is saturated, transactions are dropped rather than stored for later. There is no waiting room to be recovered from, which is the structural difference from mempool-based chains.
The practical reading: during exactly the moments a bot cares about, when a popular market opens and everyone submits at once, the ingress path is at its most contended and the drop probability is at its highest. Execution quality is not a constant; it degrades precisely when it is needed.
Why transactions drop: diagnostic table
Eight causes cover almost every real case. The value of this table is the diagnostic column, because most operators have the symptom but attribute it to the wrong cause and then optimise something irrelevant.
| Cause | Symptom | How to confirm it | Fix |
|---|---|---|---|
| Blockhash expired | Signature never appears; failures cluster after a delay | Compare send time against the blockhash slot age | Fetch the blockhash later in the build, rebuild rather than resend |
| Ingress saturation | Drops spike only during popular launches | Correlate loss rate with market-wide activity | Submit through a provider with better ingress treatment; parallel endpoints |
| Fee too low for contention | Transaction lands late or not at all on hot accounts only | Same setup lands fine on quiet markets | Raise the compute unit price for contended writable accounts |
| Leader handover | Random, unclustered losses at low volume | Loss events align with slot boundaries in your logs | Retry with a cadence shorter than the leader turn |
| Preflight rejection | Send call returns an error, not a signature | The error text names the failing instruction | Fix the instruction; do not simply disable preflight |
| RPC rate limiting | HTTP 429 or silent throttling under bursts | Provider dashboard or response headers | Budget requests, cache account data, upgrade the plan tier |
| Stale or lagging node | Blockhash is old at the moment of signing | Compare the node's slot against another endpoint | Health-check endpoints and drop nodes that lag |
| Oversized transaction | Consistent rejection on complex routes | Serialized size approaches the packet limit | Use address lookup tables or split the route |
The last row is worth expanding. A Solana transaction must fit inside a single network packet, which caps the serialized size at 1,232 bytes. Multi-hop routes with many accounts hit that ceiling, and address lookup tables exist precisely to compress the account list. A bot that works on simple pairs and mysteriously fails on complex ones is usually meeting this limit rather than encountering a network problem.
Blockhash expiry is a deadline, not a suggestion
Every transaction references a recent blockhash, and the runtime accepts it only while that hash remains within a 150-block processing window. Past that point the transaction is permanently invalid. It cannot execute late, it cannot be revived, and it will never appear on chain.
At the target slot time of roughly 400 milliseconds, 150 blocks is about a minute. Skipped slots stretch the wall-clock window somewhat, so the practical figure is usually quoted as roughly sixty to ninety seconds. Treat the shorter figure as your budget.
Two design consequences follow. First, fetch the blockhash as late as possible in the build. A hash fetched during startup and used two minutes later is already dead, and this is a genuinely common bug in hobby bots. Second, once the window closes, resending the same bytes is pointless: the transaction must be rebuilt with a fresh hash, which means re-signing and re-evaluating whether the trade still makes sense at the current price.
Expiry is a safety feature. On chains where pending transactions can sit indefinitely, a forgotten order can execute hours later at a price nobody would accept. On Solana that class of incident does not exist: the transaction dies quietly instead. Systems that need a longer window use durable nonces, which replace the recent blockhash with a stored nonce that stays valid until it is advanced. That is the correct tool for scheduled or offline-signed operations, and the wrong tool for latency-sensitive trading.
Retry design that survives contention
Default behaviour hides a lot. RPC providers typically rebroadcast a submitted transaction on your behalf at a fixed cadence until it expires. That is convenient and it is also why many operators have no idea how many attempts their trade actually took.
A deliberate retry loop looks like this:
- Decide who retries. Set the provider's internal retry count to zero and own the loop yourself, or accept the provider's behaviour and stop reasoning about attempt counts. Doing both produces duplicate traffic you cannot measure.
- Skip preflight only after validating once. Preflight simulation costs a round trip you may not be able to afford in a contested entry. Simulate during development and on configuration changes, then skip it in the hot path with the knowledge that malformed transactions will now cost fees instead of returning errors.
- Rebroadcast on a fixed short cadence. Exponential backoff is the wrong shape here, because the useful window is short and roughly uniform. A steady cadence in the low hundreds of milliseconds covers leader handovers without becoming abusive.
- Stop on any terminal condition. Signature confirmed, blockhash expired, or a price check that now fails. Retrying past the point where the trade still makes sense converts a missed opportunity into a bad fill.
- Rebuild, do not resend, after expiry. A new blockhash means a new signature, and it is the right moment to re-evaluate size, slippage and whether the market has already moved.
- Log every attempt. Attempt count, endpoint used, fee level and outcome. Without this the landing-rate measurement below is impossible.
Idempotence deserves one warning. Rebroadcasting identical signed bytes is safe, because the same signature can only execute once. Rebuilding with a fresh blockhash creates a genuinely different transaction, and if the previous one lands after you have rebuilt, both can execute. Any loop that rebuilds must first confirm the old signature is dead, not merely unconfirmed.
Measuring landing rate
Landing rate is the share of transactions you submitted that a leader actually included. It is trivial to compute and almost never reported by consumer tools. It matters most where transaction counts are high: an automated Solana volume bot submitting continuously across many wallets converts a few percentage points of landing rate into a visible share of the run, which is why the figure belongs on the interface rather than in a support reply.
The recipe, which needs nothing beyond your own logs and one RPC method:
- Log every signature at the moment of first submission, with a timestamp and the fee settings used.
- After the validity window has closed for each signature, query its status in batches with
getSignatureStatuses. - Classify each into landed and executed, landed and failed on chain, or never landed.
- Compute landing rate as landed divided by submitted, and success rate as executed divided by submitted.
- Bucket the results by market conditions, by fee level and by endpoint. The aggregate number hides the case you care about.
An illustrative session, with arithmetic you should redo against your own data rather than trust as a benchmark. Assume 500 submissions in a session. Suppose 412 signatures are found on chain, of which 39 executed as failures because slippage was exceeded. Landing rate is 412 divided by 500, or 82.4 per cent. Success rate is 373 divided by 500, or 74.6 per cent. The 88 that never landed cost nothing in fees and everything in missed trades, while the 39 on-chain failures cost fees and produced no position.
The instructive part is what each number tells you to fix. A low landing rate points at the submission path: endpoint quality, fee level, blockhash freshness, retry cadence. A high landing rate with a poor success rate points at strategy configuration: slippage tolerance, staleness of the quote, or a route that no longer reflects the pool state. Chasing latency improvements when the second pattern is the real problem is the most common misdirected optimisation in this field.
| Landing rate | On-chain success | Most likely diagnosis | Where to look first |
|---|---|---|---|
| Low | High on what lands | Submission path problem | Endpoint health, fee level, blockhash age |
| High | Low | Strategy or quote staleness problem | Slippage settings, route freshness, position sizing |
| Low | Low | Contention plus stale configuration | Whole pipeline; instrument before changing anything |
| High | High | Execution is not your bottleneck | Strategy selection and cost model |
Confirmation and honest accounting
Once a signature is confirmed, the work is not finished. The transaction result contains what actually happened, and it frequently differs from what was quoted. Parse the post-transaction token balances rather than trusting the quote, because that difference is your real slippage and it is the number that belongs in your cost model.
Choose the commitment level deliberately. Waiting for finalisation before sizing the next trade is safe and slow. Acting on processed state is fast and occasionally wrong. Most trading systems settle on confirmed for decisions and reconcile against finalised state periodically, which keeps the fast path fast without letting the ledger drift.
One further reconciliation is worth automating: compare the fee actually paid against the fee you intended. Base fees are charged per signature, priority fees are charged as a function of the compute unit price you set and the limit you declared, and a transaction that consumed less compute than it requested still pays for the limit it declared. The priority fee mechanics page works through that arithmetic in detail.
Diagnostic runbook
When landing rate falls, work down this list in order rather than changing several variables at once.
- Confirm the endpoint is not lagging: compare its current slot against a second, independent endpoint.
- Measure blockhash age at signing time. If it exceeds a few seconds, the build path is the problem, not the network.
- Check whether losses correlate with market-wide activity. If they do, it is contention and the answer is fee level and ingress quality.
- Verify you are not double-retrying, with both the provider and your own loop rebroadcasting.
- Inspect a sample of failed-on-chain transactions in an explorer and read the actual program error rather than guessing.
- Compare landing rate across endpoints on the same workload. One controlled comparison beats a week of intuition.
- Only then consider raising fees, since a higher fee on an uncontended account buys nothing at all.
Landing behaviour is the layer where automation stops being a coding exercise and becomes an operations one. It is also the layer most vendors decline to instrument, which makes the question of whether a tool reports its own landing rate one of the most efficient diagnostics you can apply to a product before buying it. The RPC and latency page covers the measurement side of the same problem.