nautechsystems/nautilus_trader · error · anyhow::Error

Finalized header base fee is invalid

Error message

Finalized header base fee is invalid

What it means

Raised in database.rs:3749 when the nullable base_fee_per_gas TEXT column of a verified finalized header row cannot be parsed as a u128. The library stores numeric header fields as text and validates on read; a value that is not a valid unsigned integer means the persisted header data is corrupt or was written by a foreign writer.

Source

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

        let (number, hash, parent_hash, timestamp, base_fee, digest) = row;
        anyhow::ensure!(
            digest == manifest_digest,
            "Finalized header manifest identity changed"
        );
        Ok(Some(ExecutionVerificationPosition {
            next_canonical_nonce: u64::try_from(nonce).context("Canonical nonce is negative")?,
            revision: u64::try_from(revision).context("Canonical nonce revision is negative")?,
            finalized_tip: ExecutionVerifiedHeader {
                number: u64::try_from(number).context("Finalized header number is negative")?,
                hash,
                parent_hash,
                timestamp: u64::try_from(timestamp)
                    .context("Finalized header timestamp is negative")?,
                base_fee_per_gas: base_fee
                    .map(|value| {
                        value
                            .parse::<u128>()
                            .map_err(|_| anyhow::anyhow!("Finalized header base fee is invalid"))
                    })
                    .transpose()?,
            },
        }))
    }

    pub(crate) async fn load_execution_verified_header(
        &self,
        chain_id: u32,
        wallet_address: &str,
        number: u64,
        manifest_digest: &str,
    ) -> anyhow::Result<Option<ExecutionVerifiedHeader>> {
        let chain_id =
            i32::try_from(chain_id).context("Verification chain ID exceeds PostgreSQL INTEGER")?;
        let number =
            i64::try_from(number).context("Finalized header number exceeds PostgreSQL BIGINT")?;
        let row = sqlx::query_as::<_, (String, String, i64, Option<String>, String)>(

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the offending row: SELECT number, base_fee_per_gas FROM execution_verified_finalized_header WHERE base_fee_per_gas IS NOT NULL AND base_fee_per_gas !~ '^[0-9]+$';
  2. Re-record the header via verification bootstrap/re-ingestion from the chain so the base fee is stored as a canonical decimal string.
  3. Restore the affected rows from a known-good backup if corruption is widespread.
  4. Do not patch the string by hand; use the writer path so formatting stays consistent.

Example fix

-- before: malformed value
UPDATE ... base_fee_per_gas = '12.5 gwei'  -- breaks u128 parse

-- after: canonical integer string in wei
-- base_fee_per_gas = '12500000000'
Defensive patterns

Strategy: validation

Validate before calling

let bad: Vec<(i64, Option<String>)> = sqlx::query_as(
    "SELECT number, base_fee_per_gas FROM execution_verified_finalized_header \
     WHERE chain_id = $1 AND base_fee_per_gas IS NOT NULL \
       AND base_fee_per_gas !~ '^[0-9]+$'",
).bind(chain_id).fetch_all(&pool).await?;
assert!(bad.is_empty(), "malformed base fee rows: {bad:?}");

Try / catch

match load_verified_header(...).await {
    Err(e) if e.to_string().contains("Finalized header base fee is invalid") => {
        // flag row corrupt; re-ingest the header from the chain
    },
    other => other?,
}

Prevention

When it happens

Trigger: Loading the finalized tip in load_execution_verification_position when base_fee_per_gas is non-null but fails "...".parse::<u128>() (empty string, negative number, decimal, non-numeric text, or a value above u128 range).

Common situations: Manual row edits or data imports that wrote malformed base-fee strings; a bug in an older writer version encoding the fee differently; corrupted rows after a partial restore/migration.

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


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