in-solana by Supanode

Transaction was not confirmed in 30.00 seconds

The client library waited 30 seconds for the transaction to reach confirmed status and gave up. This does not necessarily mean the transaction failed — it may still land.

Common causes

  1. Network congestion. High load causes transactions to queue longer than the default 30-second timeout.
  2. Insufficient priority fee. Validators prioritize transactions with higher fees. A zero or low priority fee during congestion means the transaction may be deprioritized.
  3. Transaction was dropped. The leader that received the transaction may not have included it in a block, and the RPC node’s automatic retries ran out.
  4. Client-side timeout too short. The default 30-second timeout in many SDKs is aggressive during periods of high activity.

How to fix

  1. Check if it landed anyway. Use getSignatureStatuses with the transaction signature. It may have confirmed after the timeout.
  2. If not confirmed, check if the blockhash is still valid with isBlockhashValid.
  3. If valid, resend the same signed transaction — it has the same signature, so it cannot be processed twice.
  4. If expired, rebuild with a fresh blockhash, re-sign, and send again.

How to prevent

  • Set a competitive priority fee based on getRecentPrioritizationFees.
  • Implement your own confirmation loop instead of relying on the SDK’s built-in timeout.
  • Use skipPreflight: true to eliminate the simulation round-trip.
  • Send to multiple RPC endpoints for redundancy.
import { createSolanaRpc } from "@solana/kit";

const rpc = createSolanaRpc("https://api.mainnet-beta.solana.com");

// After sending, poll manually instead of relying on SDK timeout
const signature = await rpc.sendTransaction(encodedTx, {
  encoding: "base64",
  skipPreflight: true,
}).send();

// Custom confirmation loop with blockhash expiry check
const { value: { lastValidBlockHeight } } =
  await rpc.getLatestBlockhash().send();

while (true) {
  const status = await rpc.getSignatureStatuses([signature]).send();
  if (status.value[0]?.confirmationStatus === "confirmed") {
    break; // success
  }
  const height = await rpc.getBlockHeight().send();
  if (height > lastValidBlockHeight) {
    throw new Error("Blockhash expired — retry with fresh blockhash");
  }
  await new Promise((r) => setTimeout(r, 2000));
}

FAQ

Did my transaction go through? Maybe. Always check with getSignatureStatuses before retrying. A transaction that timed out on the client side may still confirm on-chain.

Can I increase the timeout? Yes. Most client libraries accept a custom timeout or let you handle confirmation yourself. But a longer timeout alone does not fix the root cause — use priority fees and proper retry logic.

Is this the same as “transaction not landing”? Related but different. This error comes from the client library timing out. “Transaction not landing” means the transaction was never included in a block at all.

Error text variants

  • Transaction was not confirmed in 30.00 seconds
  • TransactionExpiredTimeoutError
  • Confirmation timeout

Updated: