linera-io/linera-protocol · warning · ProofError
transaction receipt not found for {tx_hash}
Error message
transaction receipt not found for {tx_hash} What it means
In HttpDepositProofClient::generate_deposit_proof, eth_getTransactionReceipt succeeded but returned null. It is wrapped as ProofError::Transient, meaning a retry may succeed — the typical cause is a transaction that is not mined or not yet indexed by the RPC node, or a hash that does not exist on this chain.
Source
Thrown at linera-bridge/src/proof/gen.rs:101
.with_context(|| format!("invalid RPC URL: {rpc_url}"))?;
let provider = ProviderBuilder::<_, _, Optimism>::default().connect_http(url);
Ok(Self {
provider: Box::new(provider),
})
}
}
#[async_trait]
impl DepositProofClient for HttpDepositProofClient {
async fn generate_deposit_proof(&self, tx_hash: B256) -> Result<DepositProof, ProofError> {
// 1. Get transaction receipt → block hash, tx index
let receipt = self
.provider
.get_transaction_receipt(tx_hash)
.await
.map_err(|e| ProofError::Transient(e.into()))?
.ok_or_else(|| {
ProofError::Transient(anyhow::anyhow!(
"transaction receipt not found for {tx_hash}"
))
})?;
let block_hash = receipt.inner.block_hash.ok_or_else(|| {
ProofError::Transient(anyhow::anyhow!("receipt missing block_hash (pending tx?)"))
})?;
let tx_index = receipt.inner.transaction_index.ok_or_else(|| {
ProofError::Transient(anyhow::anyhow!("receipt missing transaction_index"))
})?;
// 2. Get full block → header RLP
let block = self
.provider
.get_block_by_hash(block_hash)
.await
.map_err(|e| ProofError::Transient(e.into()))?
.ok_or_else(|| {View on GitHub (pinned to 6c226ddcb3)
Solutions
- Wait until the transaction is mined (1-2 confirmations) and retry
- Verify the tx hash exists on that exact network using a block explorer for the same chain
- Check --rpc-url matches the chain the deposit was sent to (e.g. Base L2)
- If it still fails after finality, the hash is wrong or the tx was dropped — stop retrying
Defensive patterns
Strategy: retry
Validate before calling
// Preflight: only attempt a proof once the receipt is mined and indexed.
loop {
let r = provider.get_transaction_receipt(tx_hash).await?;
if let Some(r) = r.filter(|r| r.inner.block_hash.is_some() && r.inner.transaction_index.is_some()) {
break;
}
tokio::time::sleep(std::time::Duration::from_secs(5)).await;
} Try / catch
match client.generate_deposit_proof(tx_hash).await {
Ok(p) => { /* submit ProcessDeposit */ }
Err(ProofError::Transient(e)) => { /* schedule retry with backoff */ }
Err(ProofError::Permanent(e)) => { /* log, alert, do not retry */ }
} Prevention
- Wait for 1-2 confirmations before generating proofs
- Confirm the tx hash exists on the exact chain the RPC serves
- Always branch on ProofError::Transient vs Permanent — the enum is the retry contract
When it happens
Trigger: Calling generate_deposit_proof(tx_hash) immediately after broadcasting the deposit transaction; --rpc-url pointing at a different chain than the one the tx was sent to; a mistyped or dropped transaction hash; an RPC node whose indexer lags behind block production.
Common situations: Public/free RPC endpoints with indexing lag; mixing up networks (Ethereum mainnet RPC with a Base tx hash); tx still in the mempool or dropped due to low gas; automations that generate proofs without waiting for confirmations.
Related errors
- receipt missing transaction_index
- receipt missing block_hash (pending tx?)
- block not found for hash {block_hash}
- block receipts not found for block {block_hash}
- header RLP hash mismatch: computed {computed_hash}, expected
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/2f3e1038b0c16fc8.
Report an issue: GitHub.