{"record":{"id":"1fa33b6835f47338","repo":"nautechsystems/nautilus_trader","slug":"invalid-tick-bounds-for-tick-lower-and-tick-upp","errorCode":null,"errorMessage":"Invalid tick bounds for {tick_lower} and {tick_upper}","messagePattern":"Invalid tick bounds for (.+?) and (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/model/src/defi/pool_analysis/profiler.rs","lineNumber":1634,"sourceCode":"    /// This function returns an error if:\n    /// - `tick_lower >= tick_upper` (invalid range).\n    /// - Ticks are not multiples of pool's tick spacing.\n    /// - Ticks are outside `MIN_TICK/MAX_TICK` bounds.\n    fn validate_ticks(&self, tick_lower: i32, tick_upper: i32) -> anyhow::Result<()> {\n        if tick_lower >= tick_upper {\n            anyhow::bail!(\"Invalid tick range: {tick_lower} >= {tick_upper}\")\n        }\n\n        if tick_lower % self.pool.tick_spacing.unwrap() as i32 != 0\n            || tick_upper % self.pool.tick_spacing.unwrap() as i32 != 0\n        {\n            anyhow::bail!(\n                \"Ticks {tick_lower} and {tick_upper} must be multiples of the tick spacing\"\n            )\n        }\n\n        if tick_lower < PoolTick::MIN_TICK || tick_upper > PoolTick::MAX_TICK {\n            anyhow::bail!(\"Invalid tick bounds for {tick_lower} and {tick_upper}\");\n        }\n        Ok(())\n    }\n\n    /// Updates all liquidity analytics.\n    fn update_liquidity_analytics(&mut self) {\n        self.analytics.liquidity_utilization_rate = self.liquidity_utilization_rate();\n    }\n\n    /// Returns the pool's active liquidity tracked by the tick map.\n    ///\n    /// This represents the effective liquidity available for trading at the current price.\n    /// The tick map maintains this value efficiently by updating it during tick crossings\n    /// as the price moves through different ranges.\n    ///\n    /// # Returns\n    /// The active liquidity (u128) at the current tick from the tick map\n    #[must_use]","sourceCodeStart":1616,"sourceCodeEnd":1652,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/defi/pool_analysis/profiler.rs#L1616-L1652","documentation":"This error is thrown by `validate_ticks` when the tick range falls outside the protocol's supported tick bounds: `tick_lower` is below `PoolTick::MIN_TICK` or `tick_upper` is above `PoolTick::MAX_TICK`. The profiler refuses to track positions whose boundaries exceed the valid tick space shared by concentrated-liquidity pools.","triggerScenarios":"Calling `process_mint`, `execute_mint`, `process_burn`, or `execute_burn` with `tick_lower < MIN_TICK` or `tick_upper > MAX_TICK`. Note the check is asymmetric: a lower tick above MAX_TICK or an upper tick below MIN_TICK is not caught by this specific condition (though the earlier lower < upper and alignment checks still apply).","commonSituations":"Converting extreme prices (near zero or near infinity) into ticks without clamping; decoding corrupted or fuzzed event data; using MIN_TICK/MAX_TICK constants of a different protocol with wider bounds.","solutions":["Clamp tick_lower to `PoolTick::MIN_TICK` and tick_upper to `PoolTick::MAX_TICK` before calling mint/burn handlers.","Validate the price range maps into the supported tick space before processing the event.","Check event decoding: guard against corrupted/garbage tick values from raw logs.","Reject the event early with a skip instead of propagating it into the profiler."],"exampleFix":"// before\nprofiler.execute_mint(owner, tick_lower, tick_upper, amount);\n// after\nuse nautilus_model::defi::pool_analysis::PoolTick;\nlet tick_lower = tick_lower.max(PoolTick::MIN_TICK);\nlet tick_upper = tick_upper.min(PoolTick::MAX_TICK);\nprofiler.execute_mint(owner, tick_lower, tick_upper, amount);","handlingStrategy":"validation","validationCode":"fn ticks_in_bounds(tick_lower: i32, tick_upper: i32) -> bool {\n    tick_lower >= PoolTick::MIN_TICK\n        && tick_upper <= PoolTick::MAX_TICK\n        && tick_lower < tick_upper\n}","typeGuard":null,"tryCatchPattern":"match profiler.execute_burn(owner, tick_lower, tick_upper, amount) {\n    Err(e) if e.to_string().contains(\"Invalid tick bounds\") => {\n        // clamp to MIN_TICK/MAX_TICK and skip or retry\n    },\n    other => other,\n}","preventionTips":["Clamp ticks to MIN_TICK/MAX_TICK immediately after price-to-tick conversion.","Sanity-check decoded event fields before feeding on-chain data into analytics.","Fuzz-test tick parsing/decoding paths for out-of-range values.","Use the protocol's own MIN_TICK/MAX_TICK constants rather than external ones."],"tags":["validation","defi","ticks","bounds"],"backgroundTag":"value-out-of-range","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}