nautechsystems/nautilus_trader · error · anyhow::Error

Invalid fee_protocol0_new '{}': {e}

Error message

Invalid fee_protocol0_new '{}': {e}

What it means

Raised while preparing a batch insert of pool fee-protocol update events: the new fee-protocol value for token0 (`fee_protocol0_new`) could not be converted to `i32` via `i32::try_from`. This fires only if the value is out of the i32 range (e.g. a u64/usize field carrying a corrupt or sentinel value), and the TryFromIntError is wrapped with the offending value in the message. The whole batch is aborted before any SQL executes.

Source

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

        let mut pool_identifiers: Vec<String> = Vec::with_capacity(len);
        let mut blocks: Vec<i64> = Vec::with_capacity(len);
        let mut transaction_hashes: Vec<String> = Vec::with_capacity(len);
        let mut transaction_indices: Vec<i32> = Vec::with_capacity(len);
        let mut log_indices: Vec<i32> = Vec::with_capacity(len);
        let mut fee_protocol0s: Vec<i32> = Vec::with_capacity(len);
        let mut fee_protocol1s: Vec<i32> = Vec::with_capacity(len);

        // Fill vectors from updates
        for update in updates {
            chain_ids.push(chain_id as i32);
            dex_names.push(update.dex.name.to_string());
            pool_identifiers.push(update.pool_identifier.to_string());
            blocks.push(update.block as i64);
            transaction_hashes.push(update.transaction_hash.clone());
            transaction_indices.push(update.transaction_index as i32);
            log_indices.push(update.log_index as i32);
            fee_protocol0s.push(i32::try_from(update.fee_protocol0_new).map_err(|e| {
                anyhow::anyhow!(
                    "Invalid fee_protocol0_new '{}': {e}",
                    update.fee_protocol0_new
                )
            })?);
            fee_protocol1s.push(i32::try_from(update.fee_protocol1_new).map_err(|e| {
                anyhow::anyhow!(
                    "Invalid fee_protocol1_new '{}': {e}",
                    update.fee_protocol1_new
                )
            })?);
        }

        // Execute batch insert with UNNEST
        sqlx::query(
            "
            INSERT INTO pool_fee_protocol_update_event (
                chain_id, dex_name, pool_identifier, block, transaction_hash, transaction_index,
                log_index, fee_protocol0_new, fee_protocol1_new

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Log and inspect the reported `fee_protocol0_new` value to find where the out-of-range number originates
  2. Validate the value against the valid fee-protocol range (0..=255 in practice) before calling the insert
  3. Check the event decoder/ABI parsing for fee_protocol0_new for width or offset bugs
  4. Clamp or reject the event upstream instead of letting try_from fail mid-batch

Example fix

// before
fee_protocol0s.push(i32::try_from(update.fee_protocol0_new).map_err(|e| {
    anyhow::anyhow!("Invalid fee_protocol0_new '{}': {e}", update.fee_protocol0_new)
})?);
// after: validate domain range first
if update.fee_protocol0_new > 255 {
    anyhow::bail!("fee_protocol0_new {} outside valid fee-protocol range", update.fee_protocol0_new);
}
fee_protocol0s.push(i32::try_from(update.fee_protocol0_new)?);
Defensive patterns

Strategy: validation

Validate before calling

fn validate_fee_protocol0(v: u64) -> anyhow::Result<()> {
    anyhow::ensure!(v <= 255, "fee_protocol0_new {v} outside fee-protocol range 0..=255");
    Ok(())
}

Type guard

fn fits_i32(v: u64) -> bool { v <= i32::MAX as u64 }

Try / catch

match validate_fee_protocol0(update.fee_protocol0_new) {
    Ok(()) => { /* proceed with insert */ },
    Err(e) => { tracing::error!("skipping malformed fee-protocol update: {e}"); }
}

Prevention

When it happens

Trigger: A `FeeProtocolUpdate` with `fee_protocol0_new` outside i32::MIN..i32::MAX (typically a u64/usize field holding a garbage or sentinel value like u64::MAX from a decoding bug) is passed to the batch fee-protocol-update insert.

Common situations: Event decoding bugs assigning raw on-chain bytes to a numeric field; ABI version changes making the fee-protocol field wider or differently packed; sentinel/uninitialized values in upstream structs.

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