nautechsystems/nautilus_trader · error · anyhow::Error

Pool {instrument_id} fee {fee} exceeds uint24

Error message

Pool {instrument_id} fee {fee} exceeds uint24

What it means

The pool's fee value could not be converted to alloy's U24 type: it exceeds 16,777,215 (2^24 - 1). Uniswap V3 encodes the fee tier in the upper 24 bits of the pool address space, so any fee outside u24 cannot appear in a valid pool. This is effectively a configuration unit error, not a chain condition.

Source

Thrown at crates/adapters/blockchain/src/execution/client.rs:1180

        if order.order_side() != OrderSide::Sell {
            anyhow::bail!(
                "Unsupported order side {}; only Sell is supported",
                order.order_side()
            );
        }

        if order.is_quote_quantity() {
            anyhow::bail!(
                "Quote-denominated quantities are not supported; quantity must be denominated in the base token"
            );
        }

        let fee = pool
            .fee
            .ok_or_else(|| anyhow::anyhow!("Pool {instrument_id} has no fee tier"))?;
        let fee = U24::try_from(fee)
            .map_err(|_| anyhow::anyhow!("Pool {instrument_id} fee {fee} exceeds uint24"))?;

        let base_token = pool.get_base_token();
        let quote_token = pool.get_quote_token();
        let quote_currency = Currency::new_checked(
            &quote_token.symbol,
            quote_token.decimals,
            0,
            &quote_token.name,
            CurrencyType::Crypto,
        )?;

        if !self
            .transaction_limits
            .allowed_token_pairs
            .contains(&(base_token.address, quote_token.address))
        {
            anyhow::bail!(
                "Token pair {} -> {} is not in the `allowed_token_pairs` allowlist",

View on GitHub (pinned to 2114cf6f76)

Solutions

  1. Correct the fee to Uniswap V3's encoding: integer hundredths of a bip, at most 1,000,000 (100%), well under the u24 ceiling
  2. Validate config at load time: assert 0 < fee <= 0xFFFFFF for every configured pool
  3. Cross-check against the on-chain pool: read fee() from the pool contract and use exactly that value

Example fix

# before: fee authored in wei-like units, exceeds u24
pool.fee = 5_000_000_000  # Pool ... fee exceeds uint24

# after: Uniswap V3 fee encoding (0.05% = 500)
pool.fee = 500
assert 0 < pool.fee <= 0xFFFFFF
Defensive patterns

Strategy: validation

Validate before calling

U24_MAX = (1 << 24) - 1

def valid_uniswap_fee(fee: int | None) -> bool:
    return fee is not None and 0 < fee <= U24_MAX

for pool in configured_pools:
    assert valid_uniswap_fee(pool.fee), f'{pool.instrument_id}: fee must be hundredths of a bip, <= {U24_MAX}'

Type guard

def is_uniswap_v3_fee(fee: int | None) -> bool:
    """Uniswap V3 fee tiers: integer hundredths of a bip, u24-encoded."""
    return isinstance(fee, int) and 0 < fee <= 0xFFFFFF

Prevention

When it happens

Trigger: submit_order where the cached pool fee was authored in the wrong units: e.g. fee entered in millionths of a percent, as a decimal fraction scaled up, or pasted from a spec sheet (values like 5_000_000_000 or 0.05*10**12).

Common situations: Copy-pasting a '0.0005' probability-style fee and multiplying by the wrong power of ten; mixing up 'fee' (bps*100) with 'tick spacing'; configuration written for a different DEX's fee units.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@2114cf6f76 (2026-08-21). Data as JSON: /api/errors/87f63ffc67150701. Report an issue: GitHub.