nautechsystems/nautilus_trader · error
Pool fee should be initialized
Error message
Pool fee should be initialized
What it means
simulate_swap_through_ticks reads self.pool.fee to get the fee tier used in swap math; if the fee was never initialized on the pool, expect panics. The fee tier is essential for computing fees accrued within each swap step, so simulation cannot proceed without it.
Solutions
- Initialize pool.fee from the factory/pool fee() call or the mint/create event before running swap simulation.
- Call check_if_initialized (or an equivalent guard) and return an error instead of proceeding when fee is None.
- Validate pool completeness (fee, tick_spacing) at profiler construction so uninitialized pools fail early with a clear error.
Example fix
// before
let fee_tier = self.pool.fee.expect("Pool fee should be initialized");
// after
let fee_tier = self.pool.fee.ok_or_else(|| anyhow::anyhow!(
"pool {} fee not initialized; cannot simulate swap", self.pool.address
))?; Defensive patterns
Strategy: validation
Validate before calling
if self.pool.fee.is_none() { return Err(anyhow::anyhow!("pool fee not initialized")); } Type guard
fn fee_tier(pool: &SharedPool) -> Option<u32> { pool.fee } Try / catch
match self.pool.fee { Some(f) => simulate_with(f), None => Err(anyhow!("fee missing")), } Prevention
- Guarantee pool.fee is set by the topology loader before simulation.
- Run a pre-flight check (fee and tick_spacing present) on every profiler used for quoting.
- Persist fee with snapshots.
When it happens
Trigger: Calling simulate_swap_through_ticks (directly or via process_swap, execute_swap, quote_swap) on a profiler whose pool.fee is None — i.e. the pool's fee rate was not captured during topology initialization.
Common situations: Quoting swaps against a pool seeded from partial data; pools discovered via RPC where the fee() call failed silently; test fixtures building SharedPool without fee.
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
- Pool tick spacing must be set
- bundled America/New_York timezone
- bundled Asia/Tokyo timezone
- bundled Australia/Sydney timezone
- bundled Europe/London timezone
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/ab9fdb65670a7b94.
Report an issue: GitHub.
Appendix: source
Thrown at crates/model/src/defi/pool_analysis/profiler.rs:494
/// # Errors
///
/// Returns error if:
/// - Pool fee is not configured
/// - Fee growth arithmetic overflows when scaling by liquidity
/// - Swap step calculations fail
///
/// # Panics
///
/// Panics if the pool fee has not been initialized.
pub fn simulate_swap_through_ticks(
&self,
amount_specified: I256,
zero_for_one: bool,
sqrt_price_limit_x96: U160,
traverse_empty_ranges: bool,
) -> anyhow::Result<SwapQuote> {
let exact_input = amount_specified.is_positive();
let fee_tier = self.pool.fee.expect("Pool fee should be initialized");
let mut current_sqrt_price = self.state.price_sqrt_ratio_x96;
let mut current_tick = self.state.current_tick;
let mut current_active_liquidity = self.tick_map.liquidity;
let mut amount_specified_remaining = amount_specified;
let mut amount_calculated = I256::ZERO;
let mut protocol_fee = U256::ZERO;
let mut lp_fee = U256::ZERO;
let mut crossed_ticks = Vec::new();
// Swapping cache variables
let fee_protocol = self.state.uniswap_v3_fee_protocol(zero_for_one);
let fee_protocol_basis_points = self.state.fee_protocol_basis_points(zero_for_one);
// Track current fee growth during swap
let mut current_fee_growth_global = if zero_for_one {
self.state.fee_growth_global_0
} else {View on GitHub (pinned to 18893faf8b)