nautechsystems/nautilus_trader · error

Pool tick spacing must be set

Error message

Pool tick spacing must be set

What it means

PoolProfiler::new() requires the SharedPool to have tick_spacing set, since the profiler's PoolState and tick map construction depend on it. The library panics via expect when pool.tick_spacing is None, i.e. the pool was never initialized with its Uniswap-V3-style tick spacing.

Source

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

    /// The event timestamp of the last processed event.
    pub last_processed_ts: Option<UnixNanos>,
    /// Flag indicating whether the pool has been initialized with a starting price.
    pub is_initialized: bool,
    /// Optional progress reporter for tracking event processing.
    reporter: Option<BlockchainSyncReporter>,
    /// The last block number that was reported (used for progress tracking).
    last_reported_block: u64,
}

impl PoolProfiler {
    /// Creates a new [`PoolProfiler`] instance for tracking pool state and events.
    ///
    /// # Panics
    ///
    /// Panics if the pool's tick spacing is not set.
    #[must_use]
    pub fn new(pool: SharedPool) -> Self {
        let tick_spacing = pool.tick_spacing.expect("Pool tick spacing must be set");
        let mut state = PoolState::default();

        if let Some((fee_protocol0, fee_protocol1)) =
            initial_protocol_fee_basis_points(pool.dex.name, pool.fee)
        {
            state.set_protocol_fee_basis_points(fee_protocol0, fee_protocol1);
        }

        Self {
            pool,
            positions: AHashMap::new(),
            tick_map: TickMap::new(tick_spacing),
            state,
            analytics: PoolAnalytics::default(),
            last_processed_event: None,
            last_processed_ts: None,
            is_initialized: false,
            reporter: None,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Populate pool.tick_spacing (e.g. from the factory's tickSpacing() call or the PoolCreated event) before constructing the profiler.
  2. Guard with if pool.tick_spacing.is_none() { /* fetch topology */ } before calling PoolProfiler::new.
  3. Reject/fail the pool earlier in ingestion so uninitialized pools never reach the profiler.

Example fix

// before
let profiler = PoolProfiler::new(pool);
// after
assert!(pool.tick_spacing.is_some(), "Pool {} tick spacing missing; fetch topology first", pool.address);
let profiler = PoolProfiler::new(pool);
Defensive patterns

Strategy: validation

Validate before calling

if pool.tick_spacing.is_none() { return Err(anyhow::anyhow!("pool tick spacing not set")); }

Type guard

fn is_pool_initialized(pool: &SharedPool) -> bool { pool.tick_spacing.is_some() && pool.fee.is_some() }

Try / catch

let profiler = if is_pool_initialized(&pool) { Some(PoolProfiler::new(pool)) } else { None };

Prevention

When it happens

Trigger: Constructing a PoolProfiler with PoolProfiler::new(pool) where pool.tick_spacing is None — e.g. a SharedPool created from incomplete topology data (factory event without tickSpacing, or a pool stub built before fetching on-chain tick spacing).

Common situations: Running pool analysis on a pool whose topology discovery step failed or was skipped; building SharedPool structs by hand for tests without setting tick_spacing; version changes where tick_spacing became optional.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/f9c48c297b1cd7b1. Report an issue: GitHub.