linera-io/linera-protocol · error
failed to check block finality — block may not exist
Error message
failed to check block finality — block may not exist
What it means
is_block_hash_finalized in the service calls ServiceEthereumClient::is_block_hash_finalized against the configured RPC endpoint and expects success. The panic means the RPC interaction failed — endpoint unreachable, rate-limited, erroring, or the block genuinely not found/not yet finalized — and it propagates as a GraphQL error to the contract's VerifyBlockHash oracle, which then also aborts. This is the service-side twin of the contract's finality check.
Source
Thrown at linera-bridge/contracts/evm-bridge/src/service.rs:224
///
/// Makes the EVM JSON-RPC calls in the service runtime so that the contract
/// sees a single deterministic oracle response (the boolean result) instead
/// of multiple raw HTTP responses with non-deterministic headers.
async fn is_block_hash_finalized(&self, block_hash: String) -> bool {
let bytes: [u8; 32] = hex::decode(block_hash.strip_prefix("0x").unwrap_or(&block_hash))
.expect("invalid hex")
.try_into()
.expect("hash must be 32 bytes");
let rpc_endpoint = self.state.rpc_endpoint.get().clone();
assert!(
!rpc_endpoint.is_empty(),
"rpc_endpoint must be configured to verify block hashes"
);
let client = ServiceEthereumClient::new(rpc_endpoint);
client
.is_block_hash_finalized(B256::from(bytes))
.await
.expect("failed to check block finality — block may not exist")
}
}
View on GitHub (pinned to 6c226ddcb3)
Solutions
- Check provider health first: a simple eth_blockNumber call to the same endpoint
- If the block is recent, wait for finality (2 epochs on Ethereum PoS) and retry VerifyBlockHash
- Verify the endpoint still reports the bridge's source_chain_id (chain mismatch makes blocks 'not exist')
- For production, use a redundant/paid RPC tier or a local node to avoid rate limits
- Treat repeated failures as an operations incident: deposits depending on the oracle will stall
Example fix
# before
linera query-service ... 'query { isBlockHashFinalized(blockHash: "0x...") }'
# -> error: failed to check block finality — block may not exist
# after — triage then retry
curl -s $RPC -X POST -H 'content-type: application/json' \
-d '{"jsonrpc":"2.0","method":"eth_getBlockByHash","params":["0x...",false],"id":1}'
# null result -> wrong network/pruned/not known yet: fix endpoint or wait for finality
# block present -> transient RPC fault: retry the query Defensive patterns
Strategy: retry
Validate before calling
// Triage before retrying the finality query:
async fn rpc_alive(url: &str) -> bool {
reqwest::Client::new().post(url).json(&serde_json::json!({
"jsonrpc": "2.0", "method": "eth_blockNumber", "params": [], "id": 1
})).send().await.map(|r| r.status().is_success()).unwrap_or(false)
} Try / catch
// Retry with backoff at the caller; the service query itself either returns
// true/false or errors:
for attempt in 0..4 {
match query_finality(&block_hash).await {
Ok(v) => return Ok(v),
Err(_) if attempt < 3 => tokio::time::sleep(Duration::from_secs(2u64 << attempt))).await,
Err(e) => return Err(e),
}
} Prevention
- Use an RPC tier with uptime guarantees or run a local node for the bridge
- Only query finality for blocks at least two epochs old
- Alert when VerifyBlockHash keeps failing — downstream deposits will stall
When it happens
Trigger: Calling VerifyBlockHash while the rpc_endpoint is down or rate-limiting; querying a block hash that does not exist on the endpoint (wrong network, pruned, or not yet known); transient network partitions between validators and the RPC provider; provider returning 429/5xx during load spikes.
Common situations: RPC provider incidents or quota exhaustion during high bridge traffic; querying finality of very recent blocks the provider has not indexed; misconfigured endpoint pointing at a different network than the block belongs to.
Related errors
- failed to query chain ID from RPC endpoint
- RegisterFungibleBridge requires an authenticated signer
- SetRpcEndpoint requires an authenticated signer
- invalid block header RLP
- receipt inclusion proof failed
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/ee5218c313ab1be3.
Report an issue: GitHub.