Transaction was not confirmed in 30 seconds

This message says something narrower than people assume. It reports that a client stopped waiting, not that the transaction failed, and the difference matters because acting on the wrong reading produces duplicate trades.

Reviewed 11 September 2026 Timeouts Troubleshooting By the Solana Volume Bot Pro team

What the message actually says

Read literally, it is a statement about your client rather than about the network. A transaction was submitted, the client polled for confirmation, a timer expired, and the client stopped waiting.

That is all. It contains no information about whether the transaction was included, whether it succeeded, or whether it will be included in a moment. The timeout is a local decision about patience, and it has been reached.

This distinction is not pedantic, because the natural response to a message containing the word "not" is to try again. Doing that without checking is how one intended trade becomes two, and the second one is not something you can undo.

It may still land

A submitted transaction remains eligible for inclusion until its blockhash expires, and that window is meaningfully longer than a typical client timeout.

So the honest state after this message is unknown, and it resolves in one of three ways. The transaction lands and succeeds, which you will discover by looking. It lands and fails for some other reason, which is also discoverable. Or the blockhash expires without inclusion, at which point it is permanently dead and cannot be revived by resending the same bytes.

The expiry guide covers that last case in more detail, and the interaction between the two is worth holding in mind: a transaction that times out at your client and then expires unseen produces two different errors describing one event.

Four causes worth separating

CauseWhat is happeningRight response
Low priority feeWaiting behind better-paying transactionsRaise the compute unit price
Network congestionEveryone is waitingRaise the fee or wait it out
Endpoint dropping checksIt landed, you cannot see itFix the endpoint, not the fee
Never submittedThe submit call itself failedCheck submission, not inclusion

The bottom two rows are the ones people rarely consider, and both point at infrastructure rather than at the market. A rate-limited endpoint can drop the confirmation polling while the transaction lands perfectly, or drop the submission itself so that nothing was ever sent. Both produce this identical message, and no amount of fee tuning addresses either. The rate limit guide covers how to recognise that pattern by what the failures correlate with.

There is a fifth situation that belongs on the list because it is invisible from the client entirely. A transaction can be included in a block that is subsequently not finalised, which means it briefly appeared and then did not. Confirmation levels exist precisely to describe this: a transaction confirmed at a lower commitment is a weaker statement than one confirmed at the highest. Scripts that poll at the fastest available commitment for speed will occasionally see something that later stops being true, and for anything involving money the safer choice is to accept a slower answer that does not change afterwards.

The duplicate trade problem

This is the reason the distinction matters commercially rather than academically.

A script that treats the timeout as failure and immediately rebuilds and resends has created a race. If the original was still in flight and both land, two swaps execute where one was intended. For a single trade that is an annoyance. Across a campaign sending hundreds of swaps during a congested period, it produces a systematic overspend that nobody notices until the confirmed volume exceeds what was configured.

The correct pattern is to check before retrying. Query the signature status; if it is confirmed, there is nothing to do. If it is not found and the blockhash has expired, build a fresh transaction. If it is not found and the blockhash is still valid, waiting is usually better than adding a second attempt to the queue.

How to check properly

  1. Keep the signature. A script that discards signatures on timeout has thrown away the only way to resolve the situation.
  2. Query its status. Confirmed, failed with an error, or not found are three different answers.
  3. If not found, check the blockhash age. Still valid means wait; expired means it is dead.
  4. If failed, read the error. The timeout told you nothing; the on-chain error tells you everything.
  5. Only then decide whether to retry, and build a new transaction rather than resending old bytes.

Step one is where most implementations fall down. A timeout handler that logs a failure and moves on has destroyed the evidence, which means every subsequent question about what happened is unanswerable.

A practical note on logging that makes all of this tractable. Record the signature, the blockhash, the submission time and the eventual resolution for every transaction, not just the failures. Without that, a campaign that produced less volume than configured is unexplainable after the fact, because the interesting question is which of the attempts landed and the evidence has been discarded. With it, the same question is a query. This is the single cheapest thing that separates operators who can answer questions about their own runs from those who cannot.

Reducing how often it happens

Some of this is unavoidable during genuinely contested periods. Most of it is not.

Price priority against current conditions. A fee set from a figure read months ago is either wasteful or insufficient, and during a busy window it is the second.

Use an endpoint provisioned for your throughput. Campaign traffic is bursty by design, and burst traffic is what rate limiters exist to stop.

Sign late and submit immediately. Every second spent between fetching a blockhash and submitting is a second removed from the window in which the transaction can land.

Pace the campaign. A schedule that sends faster than the infrastructure can serve produces this message at scale, and slowing down fixes it more reliably than any setting. That also happens to produce better-looking activity, since uneven pacing across a window is what separates ordinary flow from a burst.

Extend the client timeout. The simplest change of all, and frequently the right one. Thirty seconds is a default rather than a rule, and waiting longer costs nothing except patience while removing an entire class of false failure. The failure guide covers how this fits alongside the other errors a campaign encounters, most of which are genuinely fatal in a way this one is not.

Frequently asked questions

01Does this error mean my transaction failed?

No. It means the client gave up waiting for confirmation within its timeout. The transaction may have landed, may still land, or may never land. Those are three different outcomes and the message does not distinguish between them.

02Can the transaction still go through after the error?

Yes, as long as its blockhash has not expired. A transaction that is still valid can be included after your client stopped watching, which is why treating the timeout as a failure and immediately resending is how duplicate trades happen.

03How do I know whether it landed?

Look up the signature directly. If it appears on-chain with a success status, it landed. If it appears with an error, it failed for a specific reason worth reading. If it does not appear at all and the blockhash has expired, it never will.

04Why does this happen more during busy periods?

Because inclusion competes with everything else being submitted. When block space is contested, a transaction with a modest priority fee waits longer, and waiting longer is exactly what produces this message.

05Will raising the priority fee fix it?

It helps when the cause is inclusion priority, which is the most common case. It does nothing when the cause is a rate-limited endpoint dropping your confirmation checks, or a transaction that was never submitted successfully in the first place.

06Is it safe to retry immediately?

Not without checking. Retrying a transaction that is still in flight risks both landing, which means two trades instead of one. Check the signature status first, and if a retry is needed, build it with a fresh blockhash rather than resending the same bytes.

Keep reading

Confirmation handling that does not double-trade

Campaign swaps check status before retrying, and the cost of doing that properly sits inside the flat fee.

Open the volume console