slymnoyann/hey-1 · error · TransactionWaitError
Transaction confirmation timed out
Error message
Transaction confirmation timed out
What it means
Thrown as TransactionWaitError by useWaitForTransactionToComplete when a exponential-backoff polling loop (delay doubling up to MAX_DELAY) exhausts its attempts without the transaction reaching a confirmed status via getTransactionStatus. It's a timeout, not a rejection: the tx may still confirm later.
Source
Thrown at src/hooks/useWaitForTransactionToComplete.tsx:44
const { data } = await getTransactionStatus({
variables: { request: { txHash: hash } }
});
const status = data?.transactionStatus;
if (status?.__typename === "FinishedTransactionStatus") {
return;
}
if (status?.__typename === "FailedTransactionStatus") {
throw new TransactionWaitError(status.reason);
}
await new Promise((resolve) => setTimeout(resolve, delay));
delay = Math.min(delay * 2, MAX_DELAY);
}
throw new TransactionWaitError("Transaction confirmation timed out");
},
[getTransactionStatus]
);
return waitForTransactionToComplete;
};
export default useWaitForTransactionToComplete;
View on GitHub (pinned to 88c8f9d553)
Solutions
- Retry with the same hash: waiting is idempotent and the tx often confirms on a second pass
- Switch to a more reliable/faster RPC endpoint or official chain RPC for getTransactionStatus
- Verify the tx on a block explorer by hash before retrying — if it reverted, surface a revert error instead of looping
- Increase MAX_DELAY/attempt budget for congested periods, or use wagmi's waitForTransactionReceipt which subscribes instead of polling
Example fix
// before
throw new TransactionWaitError("Transaction confirmation timed out");
// after: include the hash and make it retryable
class TransactionWaitError extends Error {
constructor(public txHash: string) {
super(`Transaction ${txHash} confirmation timed out`);
}
}
throw new TransactionWaitError(hash); Defensive patterns
Strategy: retry
Validate before calling
// Check status on an explorer/RPC before waiting, to catch already-final or reverted txs
const receipt = await publicClient.getTransactionReceipt({ hash });
if (receipt) {
if (receipt.status === "reverted") throw new Error("Transaction reverted");
return; // already confirmed
} Type guard
const isTransactionWaitError = (e: unknown): e is Error & { name: "TransactionWaitError" } =>
e instanceof Error && e.message === "Transaction confirmation timed out"; Try / catch
try {
await waitForTransactionToComplete(hash);
} catch (e) {
if (isTransactionWaitError(e)) {
// timeout != failure: check explorer by hash; retry the wait once
await sleep(5000);
return waitForTransactionToComplete(hash);
}
throw e;
} Prevention
- Treat timeout as 'unknown status', never as a guaranteed failure — verify by hash on an explorer
- Use a reliable RPC and consider wagmi waitForTransactionReceipt (subscription) over polling
- Increase the backoff budget during known congestion; surface the tx hash to the user so they can track it
When it happens
Trigger: A slow or congested chain where the tx takes longer than the loop's total budget; the tx hash not yet visible to the status RPC/indexer (node lag, indexer behind head); RPC endpoint flakiness returning pending/unknown; or the tx actually reverted and never reaches 'success' status.
Common situations: Gas spikes or NFT mint congestion on Polygon; using a free RPC with slow finality propagation; a reorg invalidating the observed hash; API indexer (Lens Hub indexer) lagging behind the chain so status stays pending.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
AI-assisted analysis of slymnoyann/hey-1@88c8f9d553 (2026-08-28).
Data as JSON: /api/errors/f937b187b6141b92.
Report an issue: GitHub.