nautechsystems/nautilus_trader · error · InvalidMarketPriceError

market-book price must be in (0, 1)

Error message

market-book price must be in (0, 1)

What it means

While parsing order-book levels for a market order, calculate_market_price requires each level price to be strictly between 0 and 1, since Polymarket outcome prices are probabilities and 0/1 (or beyond) represent resolved or corrupt data. Offending levels raise this InvalidMarketPriceError. This protects the crossing-price walk from dividing/multiplying with nonsensical prices.

Source

Thrown at crates/adapters/polymarket/src/execution/parse.rs:759

/// Returns the crossing price and expected base quantity. If insufficient liquidity,
/// uses all available levels. If the book side is empty, returns an error.
pub fn calculate_market_price(
    book_levels: &[ClobBookLevel],
    amount: Decimal,
    side: PolymarketOrderSide,
) -> anyhow::Result<MarketPriceResult> {
    if book_levels.is_empty() {
        anyhow::bail!("Empty order book: no liquidity available for market order");
    }

    // Parse and sort levels deterministically so we never depend on API ordering.
    // BUY: asks ascending (best/lowest first). SELL: bids descending (best/highest first).
    anyhow::ensure!(amount > Decimal::ZERO, "market amount must be positive");
    let mut parsed_levels = Vec::with_capacity(book_levels.len());
    for level in book_levels {
        let price = parse_decimal_exact(&level.price).context("invalid market-book price")?;
        let size = parse_decimal_exact(&level.size).context("invalid market-book size")?;
        anyhow::ensure!(
            price > Decimal::ZERO && price < Decimal::ONE,
            InvalidMarketPriceError("market-book price must be in (0, 1)".to_string())
        );
        anyhow::ensure!(
            size >= Decimal::ZERO,
            "market-book size must be non-negative"
        );

        if !size.is_zero() {
            parsed_levels.push((price, size));
        }
    }

    if parsed_levels.is_empty() {
        anyhow::bail!("Empty order book: no valid price levels for market order");
    }

    match side {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check the market's active/resolved status before submitting market orders; skip resolved markets.
  2. Inspect the offending level price in the API response and confirm the expected 0–1 scale.
  3. Filter or reject book snapshots containing out-of-range levels before calling calculate_market_price.

Example fix

// before
let res = calculate_market_price(&levels, amount, side, precision)?;
// after
let clean: Vec<_> = levels.into_iter().filter(|l| {
    let p = Decimal::from_str(&l.price).unwrap();
    p > Decimal::ZERO && p < Decimal::ONE
}).collect();
let res = calculate_market_price(&clean, amount, side, precision)?;
Defensive patterns

Strategy: validation

Validate before calling

let ok = levels.iter().all(|l| {
    let p = Decimal::from_str(&l.price).unwrap_or_default();
    p > Decimal::ZERO && p < Decimal::ONE
});
if !ok { return Err(anyhow!("book contains out-of-range prices")); }

Type guard

fn is_valid_book_level(l: &Level) -> bool {
    Decimal::from_str(&l.price).map(|p| p > Decimal::ZERO && p < Decimal::ONE).unwrap_or(false)
}

Try / catch

match calculate_market_price(&levels, amount, side, precision) {
    Ok(r) => submit(r),
    Err(e) if e.to_string().contains("market-book price") => { log::warn!("invalid book: {e}"); refresh_book_and_retry_later(); }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: A market book fetch (via bench_submit_market) returns a level with price <= 0 or >= 1 — e.g. a resolved market stuck at 1.0, a stale/corrupt snapshot, or a price expressed in cents (55 instead of 0.55).

Common situations: Querying a book for a market that has just resolved (prices pinned at 0 or 1); a venue API change in price scaling; deserialization glitches returning placeholder values.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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