Blockhash not found, and why transactions expire

Every Solana transaction carries a recent blockhash that acts as an expiry stamp. Miss the window and the transaction is rejected outright. This is the single most common self-inflicted failure in scripted trading, and it comes from four specific patterns.

Reviewed 31 August 2026 Expiry Troubleshooting By the Solana Volume Bot Pro team

What a blockhash is doing in your transaction

Every Solana transaction includes a reference to a recent block. It looks like a technical detail and it is doing two jobs at once, both of which matter.

The first is duplicate protection. Because the blockhash pins a transaction to a moment, the same signed transaction cannot be replayed indefinitely into the future. The second is expiry: validators only keep a bounded set of recent blockhashes, and anything referencing something older than that set is rejected without being processed.

That second property is what produces the error. Your transaction was not wrong, underfunded or badly priced. It simply arrived after its stamp stopped being valid, and the network declined to look at it any further.

How long you actually have

The window is defined in blocks rather than in seconds, which is the detail that trips people up when they try to reason about it with a stopwatch.

A blockhash stays usable for a fixed number of recent blocks. Under normal conditions that works out to roughly a minute, but it is not a clock. When the network is producing blocks briskly the same number of blocks passes in less wall-clock time, so your effective window is shorter exactly when everything else is also under pressure.

The practical planning assumption should therefore be conservative. Treat the safe window as considerably less than a minute rather than as a minute, and design so that you never approach it deliberately.

Four patterns that cause it

  1. Pre-signing a batch. Building hundreds of transactions up front, signing them all, then sending over several minutes. Everything after the first stretch expires. This is by far the most common cause in campaign scripts.
  2. Slow RPC. Fetching the blockhash from a rate-limited endpoint, waiting, then building and sending. The delay is consumed before the transaction even exists.
  3. Retrying the same signed transaction. A transaction that failed once and is resubmitted unchanged carries the same expired stamp and fails again, usually in a loop that looks like the network refusing you.
  4. Human-in-the-loop delays. Anything that builds a transaction and then waits for confirmation, review or an interactive step before sending.

Notice that all four are timing and architecture problems rather than configuration ones. No fee setting and no slippage tolerance affects any of them.

The pre-signing trap, in detail

This deserves its own section because it is the one that hits volume campaigns specifically and because it looks like good engineering.

Building all your transactions in advance feels efficient. Signing is deterministic work, batching it seems clean, and it means the sending loop is simple. The problem is that signing pins the blockhash, and a campaign that spreads swaps over an hour will find that everything after the first minute or so was dead on arrival.

The symptom is distinctive and worth recognising: the first handful of transactions succeed and then a large contiguous block of them fail identically. Teams frequently misread this as being rate-limited or blocked, and go looking for a fee or RPC problem that does not exist.

The correct architecture is to sign late. Fetch, build, sign and send as one tight sequence, per transaction, at the moment you intend that swap to happen. This is one of the more meaningful differences between a competent implementation and a naive one, which the self-hosting guide covers alongside the other costs people do not budget for.

There is a related architectural point that follows from the same constraint. Because the window is short, a campaign cannot be planned as a single atomic operation submitted at once; it has to be a loop that decides, builds and sends one swap at a time over the whole window. That sounds obvious stated plainly, and it is the exact opposite of how most first implementations are structured, because the natural way to write the code is to compute the entire schedule up front. The schedule can be computed up front. The transactions cannot.

What to change

  • Sign immediately before sending. The gap between fetching a blockhash and submitting should be as close to zero as your code allows.
  • Never queue signed transactions. Queue the intent, not the signature.
  • Fetch a fresh blockhash on every retry. Resubmitting the same bytes cannot work.
  • Use an endpoint that responds quickly. A slow blockhash fetch spends your window before the transaction exists.
  • Check the commitment level you are fetching at. A blockhash taken at a very recent commitment is fresher and gives you more of the window.

One diagnostic habit is worth more than all of the above. Before changing anything, take a failed transaction signature and look at whether it appears on-chain at all. An expired blockhash usually leaves no record because it was never processed, while a transaction that failed for slippage or insufficient funds is on-chain with an error attached. That single distinction, present or absent, splits the problem space in half before you have adjusted a single setting, and it takes ten seconds.

Errors this gets confused with

Three failures look similar from the outside and need completely different responses, which is why reading the actual error rather than pattern-matching on symptoms matters.

Expired blockhash. The transaction was never eligible. Fix the timing.

Not confirmed in time. The transaction was valid but not included, which points at priority fees or congestion. Fix the fee, and note that this one does consume fees on the attempt.

Slippage exceeded. The transaction executed and reverted because the price moved past your tolerance. This is a depth and sizing problem rather than a timing one.

All three appear to the operator as swaps that did not happen, and all three have been blamed on each other by people tuning the wrong dial. The failure guide covers how to read the transaction log to tell them apart, and it is worth doing that once properly rather than adjusting settings in the dark. On the budgeting side, only one of the three is genuinely free, which the fee breakdown works through.

Frequently asked questions

01Why do Solana transactions expire?

Each transaction references a recent blockhash, which validators use to reject duplicates and to bound how long a signed transaction stays valid. Once that blockhash is old enough to have fallen out of the recent set, the transaction can no longer be processed and is rejected rather than queued.

02How long is a Solana blockhash valid?

It is bounded by a fixed number of recent blocks rather than by a clock, which works out to roughly a minute under normal conditions. Because it is measured in blocks, the wall-clock window shrinks when the network is producing blocks quickly and stretches slightly when it is not.

03Why does this happen more with bots than with wallets?

Wallets fetch a blockhash and send immediately, so the window is never a constraint. Scripts frequently build many transactions in advance, queue them, and send them over several minutes, which means the later ones are signed against a blockhash that has already expired by the time they are submitted.

04Does a failed blockhash cost fees?

A transaction rejected for an expired blockhash is generally not processed at all, so it does not incur the fee that a processed-but-failed transaction does. The real cost is the swap that did not happen and the time spent before you noticed, particularly in a campaign where a whole queue can expire together.

05How do I fix it in a script?

Fetch the blockhash immediately before signing, sign, and send without delay. Never build a batch of signed transactions to send later. On retry, always fetch a fresh blockhash rather than resubmitting the same signed transaction, which will simply be rejected again.

06Is this the same as a transaction not confirming?

No. Not confirming usually means the transaction was valid but not included in time, which points at priority fees or congestion. An expired blockhash means it was never eligible in the first place. They need different fixes, and reading the actual error rather than guessing is what separates them.

Keep reading

No script, no expiry to manage

Campaigns sign late and retry with fresh blockhashes automatically, and the cost sits inside the flat fee.

Open the volume console