nautechsystems/nautilus_trader · error
Replacement scan cursor number is negative
Error message
Replacement scan cursor number is negative
What it means
The replacement scan cursor stores the block number as a signed i64 BIGINT. When converting it back to the u64 ExecutionVerifiedHeader.number, a negative value cannot be represented and this error is raised.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:6215
AND s.wallet_address = $3
AND s.nonce = $4
",
)
.bind(intent_id)
.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()
}
View on GitHub (pinned to 18893faf8b)
Solutions
- Inspect the offending row's number value and correct or delete the corrupted row
- Audit the writer path that inserted the negative block number
- Re-run the replacement scan from a known-good finalized header
Defensive patterns
Strategy: validation
Validate before calling
let number: i64 = /* loaded cursor number */;
if number < 0 {
// treat row as corrupt: delete and rescan
} Type guard
fn valid_block_number(n: i64) -> bool { n >= 0 } Try / catch
match db.load_execution_replacement_cursor(..).await {
Err(e) if e.to_string().contains("cursor number is negative") => {
// purge corrupt row and re-record the scan
}
other => other,
} Prevention
- Never hand-edit database rows for cursors
- Add CHECK (number >= 0) constraints on header tables
- Re-scan from a known-good finalized header after corruption is detected
When it happens
Trigger: The execution_verified_finalized_header.number column (or the joined scan row) contains a negative i64, and load_execution_replacement_cursor attempts u64::try_from(number).
Common situations: Manual database edits or corrupted rows; a buggy writer inserting sign-flipped values; type confusion when another tool wrote the table.
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
- Finalized header base fee is invalid
- Canonical nonce overflow
- Replacement scan cursor timestamp is negative
- Replacement scan cursor base fee is invalid
- Stored execution payload has a truncated envelope header
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/b6ca4727ce885849.
Report an issue: GitHub.