nautechsystems/nautilus_trader · error · anyhow::Error
Finalized Swap log has no block hash
Error message
Finalized Swap log has no block hash
What it means
The library extracts the block hash from the finalized Swap RPC log and requires it to be present before cross-checking the log against the transaction receipt. A missing block_hash field means the node returned an incomplete log object, so consistency verification cannot proceed.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:4747
!log.removed
&& log.topics.first().is_some_and(|topic| topic == &signature)
&& Address::from_str(&log.address).ok() == Some(plan.pool_address)
})
.collect::<Vec<_>>();
anyhow::ensure!(
swap_logs.len() == 1,
"Finalized transaction {} emitted {} Swap logs from expected pool {}; expected exactly one",
included.tx_hash,
swap_logs.len(),
plan.pool_address
);
let log = swap_logs[0];
let log_transaction_hash = B256::from_str(&rpc_log::extract_transaction_hash(log)?)
.with_context(|| "Invalid finalized Swap log transaction hash")?;
let log_block_hash = log
.block_hash
.as_deref()
.ok_or_else(|| anyhow::anyhow!("Finalized Swap log has no block hash"))?;
anyhow::ensure!(
log_transaction_hash == included.tx_hash
&& rpc_log::extract_block_number(log)? == included.block_number
&& u64::from(rpc_log::extract_transaction_index(log)?)
== included.receipt.transaction_index
&& B256::from_str(log_block_hash)
.with_context(|| "Invalid finalized Swap log block hash")?
== included.receipt.block_hash,
"Finalized Swap log position does not match transaction {}",
included.tx_hash
);
let dex = crate::exchanges::get_dex_extended(plan.pool.chain.name, &plan.pool.dex.name)
.ok_or_else(|| {
anyhow::anyhow!(
"No RPC Swap decoder for {}:{}",
plan.pool.chain.name,
plan.pool.dex.nameView on GitHub (pinned to 18893faf8b)
Solutions
- Use a full-featured RPC provider that returns complete log objects including blockHash
- Re-fetch the log via the transaction receipt (eth_getTransactionReceipt) which always includes blockHash
- If using middleware/proxy that filters fields, disable field stripping
- In test fixtures, populate block_hash before invoking verification
Defensive patterns
Strategy: validation
Validate before calling
fn log_has_block_hash(log: &rpc_log::Log) -> bool { log.block_hash.as_deref().map(|h| h.len() == 66).unwrap_or(false) }
if !log_has_block_hash(log) { return Err(anyhow!("provider returned log without blockHash")); } Type guard
fn has_block_hash(log: &rpc_log::Log) -> Option<&str> { log.block_hash.as_deref().filter(|h| B256::from_str(h).is_ok()) } Try / catch
let log = fetch_complete_log(tx_hash).await
.map_err(|e| if is_incomplete_log(&e) { fetch_from_receipt(tx_hash).await? } else { e })?; Prevention
- Use RPC providers that return full log objects
- Prefer eth_getTransactionReceipt over raw log polling for finality checks
- Validate log completeness before verification
- Populate all fields in test log fixtures
When it happens
Trigger: An RPC provider (eth_getLogs or receipt log entry) returning a log JSON without a blockHash field — common with some lightweight or non-standard providers, reorg-pruned responses, or hand-built/mocked log fixtures.
Common situations: Switching RPC providers where one omits blockHash on filtered logs; custom indexing middleware stripping fields; unit-test fixtures built with partial log structs; calling eth_getLogs on a node with partial trace support.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Initialize event missing topics: expected 4, was {log_topics
- Profiler log has no block hash
- Missing block number
- Missing transaction hash
- Missing transaction index
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/e2d94f2096a23c4f.
Report an issue: GitHub.