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_newView on GitHub (pinned to 18893faf8b)
Solutions
- Log and inspect the reported `fee_protocol0_new` value to find where the out-of-range number originates
- Validate the value against the valid fee-protocol range (0..=255 in practice) before calling the insert
- Check the event decoder/ABI parsing for fee_protocol0_new for width or offset bugs
- 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
- Type fee-protocol fields as u8 in decoded event structs to make out-of-range unrepresentable
- Validate decoded event fields against protocol domains before persisting
- Log the raw offending value to catch decoder/ABI regressions early
- Add unit tests around event decoding widths for fee-protocol fields
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
- Invalid fee_protocol1_new '{}': {e}
- Deployment manifest pool fee is invalid
- invalid bar step: {e}
- Unsupported `OrderSide` for Binance: {value:?}
- invalid OrderSide: must be Buy or Sell, was {side}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/e05cac97e74a4f75.
Report an issue: GitHub.