nautechsystems/nautilus_trader · error
Replacement scan cursor base fee is invalid
Error message
Replacement scan cursor base fee is invalid
What it means
Data-integrity check when loading the replacement scan cursor: the stored cursor row's base_fee column decoded to a negative value, which is not a valid EIP-1559 base fee, so the cursor is rejected as corrupt.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:6224
.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!(
!scan.decisions.is_empty()
&& scan.provider_ids.len() == 3
&& scan.operator_ids.len() == 3
&& scan.failure_domain_ids.len() >= 3,View on GitHub (pinned to 18893faf8b)
Solutions
- Inspect the stored base_fee_per_gas string and correct or delete the row
- Fix the writer to store base fee as a canonical decimal u128 string
- Re-run the replacement scan to record a fresh cursor
- If the value can legitimately exceed u128, widen the parse/format
Example fix
// before
anyhow::anyhow!("Replacement scan cursor base fee is invalid")
// after
anyhow::anyhow!("Replacement scan cursor base fee is invalid: {value}") // log the offending value to diagnose hex vs decimal corruption Defensive patterns
Strategy: validation
Validate before calling
fn parse_base_fee(s: &str) -> anyhow::Result<u128> {
let v = s.parse::<u128>()
.map_err(|e| anyhow::anyhow!("base fee {s:?} not decimal u128: {e}"))?;
Ok(v)
} Type guard
fn is_decimal_u128(s: &str) -> bool {
!s.is_empty() && s.bytes().all(|b| b.is_ascii_digit()) && s.parse::<u128>().is_ok()
} Try / catch
match db.load_execution_replacement_cursor(..).await {
Err(e) if e.to_string().contains("base fee is invalid") => {
// row corrupt: delete and re-record scan
}
other => other,
} Prevention
- Always serialize base fee as canonical decimal string (no 0x, no exponent)
- Round-trip test the writer/reader format for base fee
- Include the offending value in the error message when editing the source
When it happens
Trigger: load_execution_replacement_cursor reads a non-empty base_fee_per_gas string that fails `value.parse::<u128>()` — e.g. hex-encoded, empty string, scientific notation, or truncated text.
Common situations: A writer stored the fee in hex or with 0x prefix; value exceeded u128 range; manual row edits; schema drift where the column holds a different encoding.
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
- Finalized header base fee is invalid
- Canonical nonce overflow
- Replacement scan cursor number is negative
- Replacement scan cursor timestamp is negative
- Stored execution payload has a truncated envelope header
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/90b052ea2ee615ce.
Report an issue: GitHub.