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
- Check the market's active/resolved status before submitting market orders; skip resolved markets.
- Inspect the offending level price in the API response and confirm the expected 0–1 scale.
- 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
- Check market active/resolved status before trading
- Refetch the book snapshot when invalid levels are seen
- Assert price scaling in feed ingestion tests
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
- Empty order book: no liquidity available for market order
- Empty order book: no valid price levels for market order
- Book snapshot hash mismatch for {}: expected {expected}, com
- Empty book snapshot for {instrument_id}
- market amount must be positive
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/921b0940cf5eb8b3.
Report an issue: GitHub.