nautechsystems/nautilus_trader · error · anyhow::Error
Invalid tick range: {tick_lower} >= {tick_upper}
Error message
Invalid tick range: {tick_lower} >= {tick_upper} What it means
validate_ticks enforces Uniswap-v3 position constraints: tick_lower must be strictly less than tick_upper, both must be multiples of the pool's tick spacing, and both within MIN_TICK/MAX_TICK. It bails immediately when tick_lower >= tick_upper since such a range defines no valid position. Used by both mint and burn processing.
Source
Thrown at crates/model/src/defi/pool_analysis/profiler.rs:1622
// Safe to cast to u64: Since active_liquidity <= total_liquidity,
// the ratio is guaranteed to be <= PRECISION (1_000_000), which fits in u64
ratio.to::<u64>() as f64 / f64::from(PRECISION)
}
/// Validates tick range for position operations.
///
/// Ensures ticks are properly ordered, aligned to tick spacing, and within
/// valid bounds. Used by all position-related operations.
///
/// # Errors
///
/// This function returns an error if:
/// - `tick_lower >= tick_upper` (invalid range).
/// - Ticks are not multiples of pool's tick spacing.
/// - Ticks are outside `MIN_TICK/MAX_TICK` bounds.
fn validate_ticks(&self, tick_lower: i32, tick_upper: i32) -> anyhow::Result<()> {
if tick_lower >= tick_upper {
anyhow::bail!("Invalid tick range: {tick_lower} >= {tick_upper}")
}
if tick_lower % self.pool.tick_spacing.unwrap() as i32 != 0
|| tick_upper % self.pool.tick_spacing.unwrap() as i32 != 0
{
anyhow::bail!(
"Ticks {tick_lower} and {tick_upper} must be multiples of the tick spacing"
)
}
if tick_lower < PoolTick::MIN_TICK || tick_upper > PoolTick::MAX_TICK {
anyhow::bail!("Invalid tick bounds for {tick_lower} and {tick_upper}");
}
Ok(())
}
/// Updates all liquidity analytics.
fn update_liquidity_analytics(&mut self) {View on GitHub (pinned to 18893faf8b)
Solutions
- Swap or sort the tick arguments so tick_lower < tick_upper before calling
- Validate the tick range (and spacing alignment) at your call site before invoking mint/burn
- Check the event decoder: ticks should be i32 read from the correct log fields
- Skip mint/burn events with invalid tick ranges as data errors, logging them for review
Example fix
// before profiler.process_mint(owner, tick_upper, tick_lower, amount)?; // after let (lower, upper) = (tick_lower.min(tick_upper), tick_lower.max(tick_upper)); profiler.process_mint(owner, lower, upper, amount)?;
Defensive patterns
Strategy: validation
Validate before calling
anyhow::ensure!(tick_lower < tick_upper, "invalid tick range"); anyhow::ensure!(tick_lower % spacing == 0 && tick_upper % spacing == 0, "ticks off spacing");
Type guard
fn valid_tick_range(lower: i32, upper: i32, spacing: i32) -> bool {
lower < upper && lower % spacing == 0 && upper % spacing == 0
} Try / catch
match profiler.process_mint(owner, lower, upper, amount) {
Err(e) if e.to_string().contains("Invalid tick range") => { /* skip malformed event */ }
other => other?,
} Prevention
- Order tick arguments (min, max) at every call site
- Validate tick spacing alignment before mint/burn simulation
- Check tick decoding (i32 from correct log fields)
- Skip and log events with invalid tick ranges as data errors
When it happens
Trigger: Calling process_mint/process_burn/execute_mint/execute_burn with tick_lower >= tick_upper — e.g. swapped arguments, decoded tick values from malformed events, or burns on positions that were never validated.
Common situations: Argument order mistakes when calling the API; event decoding bugs producing negative/garbage ticks; MIN_TICK==MAX_TICK style sentinel misuse; ticks decoded as unsigned then truncated.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Cannot quote swap with zero amount
- Price limit must be less than current price for zero_for_one
- Price limit must be greater than current price for one_for_z
- No liquidity
- Position liquidity {} is less than the requested burn amount
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/9a9c11d00b9ddb4a.
Report an issue: GitHub.