nautechsystems/nautilus_trader · error

Liquidity {} exceeds i128::MAX

Error message

Liquidity {} exceeds i128::MAX

What it means

`PoolProfiler::process_burn` applies a burn by subtracting a signed `i128` liquidity delta from the position. The burn's `position_liquidity` (u128) must fit in `i128`; otherwise `i128::try_from` fails with this error. Like the mint counterpart, this indicates event data whose liquidity is implausibly large (corrupt decode or adversarial input).

Source

Thrown at crates/model/src/defi/pool_analysis/profiler.rs:1058

    /// # Errors
    ///
    /// This function returns an error if:
    /// - Pool is not initialized.
    /// - Tick range is invalid.
    /// - Position updates fail.
    pub fn process_burn(&mut self, update: &PoolLiquidityUpdate) -> anyhow::Result<()> {
        self.check_if_initialized(PoolEventKind::Burn)?;

        if self.check_if_already_processed(update.block, update.transaction_index, update.log_index)
        {
            return Ok(());
        }

        self.validate_ticks(update.tick_lower, update.tick_upper)?;

        // Update the position with a negative liquidity delta for the burn
        let liquidity_delta = i128::try_from(update.position_liquidity).map_err(|_| {
            anyhow::anyhow!("Liquidity {} exceeds i128::MAX", update.position_liquidity)
        })?;
        let location = self.event_location(
            PoolEventKind::Burn,
            update.block,
            update.transaction_index,
            update.log_index,
        );

        self.update_position(
            &update.owner,
            update.tick_lower,
            update.tick_upper,
            -liquidity_delta,
            update.amount0,
            update.amount1,
        )
        .map_err(|e| Self::wrap_liquidity_error(e, location))?;

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check the ABI/log decoding path that produces `position_liquidity` for the Burn event.
  2. Pre-validate burns and skip those with liquidity > i128::MAX (real pools never reach this).
  3. Handle the error per-event and continue profiling instead of aborting.
  4. If this reproduces on known-good pools, file/inspect the decoder — the data source, not the profiler, is at fault.

Example fix

// before
profiler.process(update)?; // burns with corrupt liquidity abort the run
// after
if update.position_liquidity > i128::MAX as u128 {
    warn!("skip burn: liquidity {} exceeds i128::MAX", update.position_liquidity);
} else {
    profiler.process(update)?;
}
Defensive patterns

Strategy: validation

Validate before calling

fn burn_liquidity_representable(l: u128) -> bool { l <= i128::MAX as u128 }

Try / catch

if let Err(e) = profiler.process(update) {
    if e.to_string().contains("exceeds i128::MAX") { warn!("skipping bad burn event"); }
    else { return Err(e); }
}

Prevention

When it happens

Trigger: Calling `process_burn` (e.g. via `PoolProfiler::process` on a Burn event) where `update.position_liquidity > i128::MAX`.

Common situations: Malformed Burn event decoding during chain indexing; fuzzed/test data with extreme u128 values; wrong word offset when parsing burn liquidity.

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