nautechsystems/nautilus_trader · error · anyhow::Error
Invalid block-scoped snapshot hash
Error message
Invalid block-scoped snapshot hash
What it means
For a block-scoped snapshot row, the stored transaction_hash must be a valid 32-byte B256 hex value; the ingestion-time block hash doubles as the snapshot's transaction hash. If the field cannot be parsed as B256, the row is malformed and processing stops. The subsequent check (not this error) also requires it to equal the expected block hash.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:3976
canonical_block.hash == expected_block_hash,
"Pool state block {} changed from {} to {}; refresh the profiler before execution",
position.number,
expected_block_hash,
canonical_block.hash
);
let snapshot_transaction = position.transaction_index == BLOCK_SCOPED_SNAPSHOT_INDEX;
let snapshot_log = position.log_index == BLOCK_SCOPED_SNAPSHOT_INDEX;
anyhow::ensure!(
snapshot_transaction == snapshot_log,
"Pool state at block {} has an invalid partial snapshot watermark",
position.number
);
if snapshot_transaction {
let snapshot_hash = B256::from_str(&position.transaction_hash)
.with_context(|| "Invalid block-scoped snapshot hash")?;
anyhow::ensure!(
snapshot_hash == expected_block_hash,
"Block-scoped snapshot hash {snapshot_hash} does not match ingestion hash {expected_block_hash}"
);
} else {
validate_profiler_event_verified(
position,
expected_block_hash,
plan.pool_address,
&plan.pool,
verification,
)
.await?;
}
let ancestry = verified_value(
verification
.verify_header_window(canonical_block, head.number)
.await,View on GitHub (pinned to 18893faf8b)
Solutions
- Re-ingest the block-scoped snapshot so transaction_hash is written as the proper block hash hex.
- Backfill the row with the correct block hash (0x-prefixed 64 hex chars) if re-ingestion isn't possible.
- Upgrade or fix the indexer component that produced the malformed hash.
- Validate snapshot rows at write time to reject non-B256 values early.
Example fix
// before
position.transaction_hash = "snapshot".to_string();
// after: store the block hash as the snapshot marker
position.transaction_hash = format!("{:#x}", block_hash); // valid B256 hex Defensive patterns
Strategy: validation
Validate before calling
if B256::from_str(&position.transaction_hash).is_err() {
anyhow::bail!("snapshot row at block {} has malformed transaction_hash", position.number);
} Type guard
fn valid_snapshot_hash(position: &PoolStatePosition) -> bool {
B256::from_str(&position.transaction_hash).is_ok()
} Prevention
- Only write 0x-prefixed 32-byte hex into transaction_hash.
- Validate hex fields at ingest boundaries (deserialize into B256).
- Backfill placeholder hashes by re-running the indexer for affected blocks.
When it happens
Trigger: Parsing position.transaction_hash with B256::from_str fails during block-scoped-snapshot handling — e.g. the field holds a placeholder, empty string, non-hex text, or wrong-length hash.
Common situations: An indexer version writing placeholder snapshot hashes; manual data fixes with malformed hex; a schema change that repurposed transaction_hash; snapshots copied across deployments with different encodings.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Chart function must be callable, was {type(func)}
- Chart '{name}' not found.{suggestion_text} Available charts:
- plotly is required for visualization. Install it with: pip i
- A BacktestNode is required for the bars_with_fills chart
- Invalid bar specification format: {}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/6a0643641d197de7.
Report an issue: GitHub.