nautechsystems/nautilus_trader · error · anyhow::Error

expected 2 impact prices, received {len}

Error message

expected 2 impact prices, received {len}

What it means

normalize_all_dex_asset_ctx_entry parses the impactPrices field of a DEX asset context (DEX perp market summary data). The API is expected to return exactly a [bid, ask] pair of strings; any other array length triggers this bail. This guards against malformed or changed upstream payload shapes before they can propagate into Price values.

Source

Thrown at crates/adapters/hyperliquid/src/websocket/handler.rs:1331

            .mid_px
            .map(|value| Price::from_decimal(value).map_err(anyhow::Error::msg))
            .transpose()?;
        let funding_rate = ctx.funding;
        let open_interest = ctx.open_interest;
        let premium = ctx.premium;
        let day_ntl_volume = ctx.shared.day_ntl_vlm;
        let day_base_volume = ctx
            .shared
            .day_base_vlm
            .ok_or_else(|| anyhow::anyhow!("missing dayBaseVlm"))?;
        let impact_prices = match ctx.shared.impact_pxs {
            Some(values) => match values.as_slice() {
                [bid, ask] => Some(HyperliquidImpactPrices {
                    bid: bid.parse::<Price>().map_err(anyhow::Error::msg)?,
                    ask: ask.parse::<Price>().map_err(anyhow::Error::msg)?,
                }),
                other => {
                    anyhow::bail!("expected 2 impact prices, received {}", other.len());
                }
            },
            None => None,
        };

        Ok(HyperliquidDexAssetCtx {
            dex: dex.to_string(),
            instrument_id,
            mark_price,
            oracle_price,
            prev_day_price,
            mid_price,
            impact_prices,
            funding_rate,
            open_interest,
            premium,
            day_ntl_volume,
            day_base_volume,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the raw payload for the offending entry and confirm its impactPrices shape; update parsing if the API changed.
  2. Update/upgrade the adapter to a version matching the current Hyperliquid API schema (or vice versa: pin the API behavior).
  3. Handle entries with missing impact prices gracefully by skipping them or logging a warning instead of treating them as fatal, if the domain allows.
  4. Add a payload-shape test/mock against a recorded real response to catch regressions early.

Example fix

// before
other => {
    anyhow::bail!("expected 2 impact prices, received {}", other.len());
}
// after
other => {
    tracing::warn!("unexpected impactPrices count ({}), skipping entry", other.len());
    None
}
Defensive patterns

Strategy: validation

Validate before calling

// validate before parsing
if let Some(v) = entry.get("impactPrices") {
    let arr = v.as_array().ok_or("impactPrices not an array")?;
    if arr.len() != 2 {
        return Err(anyhow!("expected 2 impact prices, got {}", arr.len()));
    }
}

Type guard

fn is_bid_ask_pair(v: &serde_json::Value) -> Option<&Vec<serde_json::Value>> {
    v.as_array().filter(|a| a.len() == 2)
}

Prevention

When it happens

Trigger: Receiving an allMids/DEX asset-context entry whose impactPrices array has 0, 1, 3, or more elements instead of exactly 2. Happens when the Hyperliquid DEX payload deviates from the documented [bid, ask] shape (schema change, partial data, or unexpected entry type).

Common situations: A Hyperliquid API schema change altering impactPrices; an edge-case market entry with missing/empty impact prices; proxy or mocked endpoints returning abbreviated payloads; parsing a payload captured from a different API version.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


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