nautechsystems/nautilus_trader · error · anyhow::Error
Finalized block timestamp overflows nanoseconds
Error message
Finalized block timestamp overflows nanoseconds
What it means
Emitted when block.timestamp.checked_mul(NANOSECONDS_IN_SECOND) overflows while converting the finalized block's timestamp to nanoseconds for the fill's ts_event. A compliant EVM node reports timestamps in seconds, which cannot overflow a u64 when scaled by 1e9; overflow therefore indicates the node reported the timestamp in non-second units (e.g., milliseconds) or returned garbage.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:2269
"Finalized Swap input {base_amount} does not match the persisted amount {}",
plan.amount_in
);
let block = executor
.http_rpc_client
.block_by_number(included.block_number, false)
.await?;
anyhow::ensure!(
block.hash == included.receipt.block_hash,
"Finalized block {} changed from {} to {} before fill emission",
included.block_number,
included.receipt.block_hash,
block.hash
);
let timestamp_ns = block
.timestamp
.checked_mul(NANOSECONDS_IN_SECOND)
.ok_or_else(|| anyhow::anyhow!("Finalized block timestamp overflows nanoseconds"))?;
let mut swap = event.to_pool_swap(
plan.pool.chain.clone(),
plan.instrument_id,
plan.pool.pool_identifier,
UnixNanos::from(timestamp_ns),
);
swap.calculate_trade_info(&plan.pool.token0, &plan.pool.token1, None)?;
let trade = swap
.trade_info
.as_ref()
.ok_or_else(|| anyhow::anyhow!("Finalized Swap has no calculated trade information"))?;
anyhow::ensure!(
trade.order_side == OrderSide::Sell,
"Finalized Swap side {} does not match Sell order",
trade.order_side
);
let gas_cost = included
.receiptView on GitHub (pinned to 2114cf6f76)
Solutions
- Fetch the block with eth_getBlockByNumber and inspect the timestamp magnitude: seconds since epoch should be ~1.7e9; ~1.7e12 means milliseconds.
- Switch to a consensus-compliant endpoint that reports seconds.
- If you control the fixture/stub, generate timestamps in seconds.
- Report non-second timestamps to the node operator as a spec violation.
Defensive patterns
Strategy: validation
Validate before calling
const MIN_TS: u64 = 1_430_000_000; // ~2015, post-genesis sanity floor
const MAX_TS: u64 = 4_102_444_800; // year 2100
fn timestamp_is_seconds(ts: u64) -> bool { (MIN_TS..=MAX_TS).contains(&ts) } Type guard
fn block_timestamp_is_plausible(block: &RpcBlock) -> bool {
timestamp_is_seconds(block.timestamp)
} Try / catch
Catch the overflow, log the raw block.timestamp value, and treat the endpoint as non-compliant until its timestamp units are fixed; do not divide ad hoc to 'recover'.
Prevention
- Monitor block timestamps from your RPC endpoints and alert when the magnitude leaves the seconds range.
- Prefer nodes you control or reputable providers over custom gateways for execution.
When it happens
Trigger: RPC node or proxy reporting block timestamps in milliseconds/microseconds instead of seconds; a misbehaving or malicious endpoint returning near-u64::MAX timestamps; custom chains that overload the timestamp field with non-second semantics.
Common situations: L2 nodes or gateway providers with non-standard timestamp units; test stubs generating block fixtures with arbitrary large timestamp values.
Related errors
- Finalized transaction gas commission overflow
- Finalized block {} does not contain transaction {}
- Finalized execution transaction {tx_hash} no longer has a re
- Persisted terminal transaction {tx_hash} is not stable at th
- Latest block {} has no base fee
AI-assisted analysis of nautechsystems/nautilus_trader@2114cf6f76 (2026-08-21).
Data as JSON: /api/errors/46935283d2970b51.
Report an issue: GitHub.