nautechsystems/nautilus_trader · error

Replacement scan cursor timestamp is negative

Error message

Replacement scan cursor timestamp is negative

What it means

Data-integrity check when loading the replacement scan cursor: the stored cursor row's timestamp column decoded to a negative value, which cannot be a valid Unix timestamp, so the cursor is rejected as corrupt.

Source

Thrown at crates/adapters/blockchain/src/cache/database.rs:6220

        .bind(chain_id)
        .bind(wallet_address)
        .bind(nonce)
        .fetch_optional(&self.pool)
        .await
        .context("failed to load replacement scan cursor")?;
        row.map(
            |(number, hash, parent_hash, timestamp, base_fee, stored_digest)| {
                anyhow::ensure!(
                    stored_digest == manifest_digest,
                    "Replacement scan manifest identity changed"
                );
                Ok(ExecutionVerifiedHeader {
                    number: u64::try_from(number)
                        .context("Replacement scan cursor number is negative")?,
                    hash,
                    parent_hash,
                    timestamp: u64::try_from(timestamp)
                        .context("Replacement scan cursor timestamp is negative")?,
                    base_fee_per_gas: base_fee
                        .map(|value| {
                            value.parse::<u128>().map_err(|_| {
                                anyhow::anyhow!("Replacement scan cursor base fee is invalid")
                            })
                        })
                        .transpose()?,
                })
            },
        )
        .transpose()
    }

    pub(crate) async fn record_execution_replacement_scan(
        &self,
        scan: &ExecutionReplacementScan<'_>,
    ) -> anyhow::Result<()> {
        anyhow::ensure!(

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect and fix or delete the row with the negative timestamp
  2. Fix or re-run the writer that produced the negative timestamp
  3. Re-record the replacement scan so a valid header is stored
Defensive patterns

Strategy: validation

Validate before calling

let ts: i64 = /* loaded timestamp */;
if ts < 0 {
    // corrupt row: purge and re-record the scan
}

Type guard

fn valid_timestamp(ts: i64) -> bool { ts >= 0 }

Try / catch

match db.load_execution_replacement_cursor(..).await {
    Err(e) if e.to_string().contains("cursor timestamp is negative") => {
        // delete corrupted row and re-run record_execution_replacement_scan
    }
    other => other,
}

Prevention

When it happens

Trigger: load_execution_replacement_cursor reads a row whose execution_verified_finalized_header.timestamp is negative and calls u64::try_from(timestamp).

Common situations: Corrupted or hand-edited rows; clock skew bugs in the writer producing negative values; schema/type confusion from external tooling.

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/d6b74ee4a5efc07a. Report an issue: GitHub.