nautechsystems/nautilus_trader · error · anyhow::Error

Verified inclusion timestamp exceeds nanoseconds

Error message

Verified inclusion timestamp exceeds nanoseconds

What it means

This library verifies a blockchain transaction inclusion by converting the inclusion block's timestamp (in seconds) into nanoseconds for the UnixNanos domain type. The checked_mul against NANOSECONDS_IN_SECOND fails when the seconds value would overflow the i64 nanoseconds range, so the library aborts rather than producing a corrupted timestamp.

Source

Thrown at crates/adapters/blockchain/src/execution/client.rs:4689

        ts_event,
        ts_event,
        false,
        false,
    );
    emitter.try_send_order_event(OrderEventAny::Rejected(rejected))
}

fn finalized_inclusion_time(included: &IncludedTransaction) -> anyhow::Result<UnixNanos> {
    let inclusion = &included.finality.inclusion_header;
    anyhow::ensure!(
        inclusion.number == included.block_number
            && inclusion.hash == included.receipt.block_hash.to_string(),
        "Verified inclusion header does not match the finalized receipt"
    );
    let timestamp = inclusion.timestamp;
    let nanos = timestamp
        .checked_mul(NANOSECONDS_IN_SECOND)
        .ok_or_else(|| anyhow::anyhow!("Verified inclusion timestamp exceeds nanoseconds"))?;
    Ok(UnixNanos::from(nanos))
}

fn execution_event_id(tx_hash: B256, event: &[u8]) -> UUID4 {
    let mut identity = Vec::with_capacity(tx_hash.len() + event.len());
    identity.extend_from_slice(tx_hash.as_slice());
    identity.extend_from_slice(event);
    let digest = keccak256(identity);
    let mut bytes = [0u8; 16];
    bytes.copy_from_slice(&digest[..16]);
    UUID4::from_bytes(bytes)
}

struct FinalizedSwapFill {
    venue_order_id: VenueOrderId,
    trade_id: TradeId,
    last_qty: Quantity,
    last_px: Price,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Verify the RPC node returns block.timestamp in seconds (hex-decoded) and not milliseconds; if in ms, divide by 1000 before this call
  2. Re-fetch the inclusion header from a trusted endpoint; a poisoned timestamp usually indicates a bad upstream response
  3. Check that NANOSECONDS_IN_SECOND and the arithmetic type width match the UnixNanos::from contract for your platform
  4. Clamp or validate timestamp <= i64::MAX / 1_000_000_000 before calling the verification API

Example fix

// before
let nanos = timestamp.checked_mul(NANOSECONDS_IN_SECOND)?;
// after
let timestamp_secs = if timestamp > 1_000_000_000_000 { timestamp / 1000 } else { timestamp };
let nanos = timestamp_secs.checked_mul(NANOSECONDS_IN_SECOND)?;
Defensive patterns

Strategy: validation

Validate before calling

const MAX_TS_SECS: u64 = (i64::MAX as u64) / 1_000_000_000;
if inclusion.timestamp > MAX_TS_SECS {
    return Err(anyhow!("timestamp {} too large for nanosecond conversion", inclusion.timestamp));
}

Type guard

fn ts_in_nanos_range(ts: u64) -> bool { ts <= (i64::MAX as u64) / 1_000_000_000 }

Try / catch

match timestamp.checked_mul(NANOSECONDS_IN_SECOND) {
    Some(nanos) => Ok(UnixNanos::from(nanos)),
    None => { log::error!("timestamp overflow: {}", timestamp); Err(...) }
}

Prevention

When it happens

Trigger: Calling the finalized-swap verification flow when inclusion.timestamp is an absurdly large value (e.g. corrupted RPC response, timestamp in milliseconds instead of seconds, or u64 max sentinel from a malicious/faulty node) so that timestamp * 1e9 exceeds the integer range.

Common situations: A misconfigured or buggy RPC provider returning timestamps already in milliseconds or nanoseconds; a mocked/fixture header with a placeholder timestamp; integer width differences after a dependency upgrade changing UnixNanos storage.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/daa7806ecb77d503. Report an issue: GitHub.