nautechsystems/nautilus_trader · error

`price_precisions` length ({}) must match `instrument_ids` l

Error message

`price_precisions` length ({}) must match `instrument_ids` length ({})

What it means

The live Databento client's `subscribe` accepts an optional `price_precisions` list that must be parallel to `instrument_ids` (one precision per instrument, entries may be None). When the list is provided but its length differs from the instrument list, the client bails before subscribing.

Source

Thrown at crates/adapters/databento/src/live.rs:191

    ///
    /// # Errors
    ///
    /// Returns an error if symbology, schema, timestamp, or precision inputs are invalid,
    /// or if the command cannot be sent to the feed handler.
    #[expect(clippy::needless_pass_by_value)]
    pub fn subscribe(
        &mut self,
        schema: String,
        instrument_ids: Vec<InstrumentId>,
        start: Option<u64>,
        snapshot: Option<bool>,
        price_precisions: Option<Vec<Option<u8>>>,
        stype_in: Option<String>,
    ) -> anyhow::Result<()> {
        if let Some(precisions) = &price_precisions
            && precisions.len() != instrument_ids.len()
        {
            anyhow::bail!(
                "`price_precisions` length ({}) must match `instrument_ids` length ({})",
                precisions.len(),
                instrument_ids.len()
            );
        }

        let symbols: Vec<String> = instrument_ids
            .iter()
            .map(|id| id.symbol.to_string())
            .collect();
        let first_symbol = symbols
            .first()
            .ok_or_else(|| anyhow::anyhow!("No symbols provided"))?;
        let stype_in = match stype_in {
            Some(stype_in) => dbn::SType::from_str(&stype_in)?,
            None => infer_symbology_type(first_symbol),
        };
        let symbols: Vec<&str> = symbols.iter().map(String::as_str).collect();

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Make `price_precisions` exactly the same length as `instrument_ids`, using None entries for defaults.
  2. Pass `price_precisions=None` if you don't need per-instrument precisions.
  3. In Python, zip or derive precisions from the same source as the instrument IDs.
  4. Assert lengths match before calling subscribe.

Example fix

// before
precisions = [8, 4]  # 2 entries
await client.subscribe(instrument_ids, price_precisions=precisions)  # 3 instruments
// after
precisions = [8, None, 4]  # one entry (or None) per instrument
await client.subscribe(instrument_ids, price_precisions=precisions)
Defensive patterns

Strategy: validation

Validate before calling

if price_precisions is not None:
    assert len(price_precisions) == len(instrument_ids), (
        f"price_precisions ({len(price_precisions)}) must match instrument_ids ({len(instrument_ids)})")

Prevention

When it happens

Trigger: Calling `subscribe` (directly or via `py_subscribe`) with `instrument_ids` of length N and `price_precisions` = Some(vec) of length != N, including passing an empty precision list with non-empty instruments.

Common situations: Building the precision list in Python from a different collection than the instrument IDs; filtering instruments but forgetting to filter precisions; passing price_precisions=[] thinking it means 'use defaults'.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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