nautechsystems/nautilus_trader · error · anyhow::Error

Error decoding `stype_in_symbol`: {e}

Error message

Error decoding `stype_in_symbol`: {e}

What it means

Raised while processing a Databento SymbolMappingMsg when the adapter cannot UTF-8-decode the `stype_in` symbol field from the record. Databento stores symbols as fixed byte arrays with a length byte; a corrupt, truncated, or invalid-length field makes `stype_in_symbol()` return a decode error, which the adapter propagates as anyhow error while updating the price precision map.

Source

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

        .map_err(|e| anyhow::anyhow!("on_symbol_mapping failed for {msg:?}: {e}"))?;
    instrument_id_map.remove(&msg.header().instrument_id);
    Ok(())
}

fn update_price_precision_map_with_symbol_mapping_msg(
    msg: &dbn::SymbolMappingMsg,
    price_precision_overrides: &AHashMap<Symbol, u8>,
    subscription_price_precision_map: &mut AHashMap<u32, u8>,
) -> anyhow::Result<()> {
    subscription_price_precision_map.remove(&msg.hd.instrument_id);

    if price_precision_overrides.is_empty() {
        return Ok(());
    }

    let stype_in_symbol = msg
        .stype_in_symbol()
        .map_err(|e| anyhow::anyhow!("Error decoding `stype_in_symbol`: {e}"))?;
    let stype_out_symbol = msg
        .stype_out_symbol()
        .map_err(|e| anyhow::anyhow!("Error decoding `stype_out_symbol`: {e}"))?;

    let price_precision = [stype_in_symbol, stype_out_symbol]
        .into_iter()
        .find_map(|symbol| {
            price_precision_overrides
                .get(&Symbol::from_str_unchecked(symbol))
                .copied()
        });

    if let Some(price_precision) = price_precision {
        subscription_price_precision_map.insert(msg.hd.instrument_id, price_precision);
    }

    Ok(())
}

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Upgrade the `databento-dbn` crate in both the adapter and any user code to matching, current versions so record decoding agrees
  2. Re-establish the live session; if reproducible, capture the raw stream and report the malformed SymbolMappingMsg to Databento support
  3. If precision overrides are not actually needed for that subscription, pass an empty `price_precision_overrides` so symbol mapping messages skip decoding entirely
  4. Log and skip the failing record instead of failing the session by handling the error in the run_session record loop

Example fix

// before
let stype_in_symbol = msg
    .stype_in_symbol()
    .map_err(|e| anyhow::anyhow!("Error decoding `stype_in_symbol`: {e}"))?;
// after: tolerate a single bad record without killing the session
let stype_in_symbol = match msg.stype_in_symbol() {
    Ok(s) => s,
    Err(e) => {
        log::warn!("Skipping symbol mapping msg: {e}");
        return Ok(());
    }
};
Defensive patterns

Strategy: try-catch

Validate before calling

// ensure overrides exist only if symbols are well-formed UTF-8
if !price_precision_overrides.is_empty() {
    // decoding only happens when overrides are non-empty
}

Type guard

fn has_overrides(overrides: &AHashMap<Symbol, u8>) -> bool { !overrides.is_empty() }

Try / catch

match result {
    Ok(()) => {},
    Err(e) if e.to_string().contains("stype_in_symbol") => log::warn!("bad symbol mapping record: {e}"),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: A live Databento session (run_session) receives a SymbolMappingMsg while `price_precision_overrides` is non-empty, and the record's stype_in symbol bytes cannot be decoded (invalid UTF-8 or bad length prefix in the DBN record).

Common situations: Corrupted DBN stream data from the live gateway, decoding with a mismatched dbn crate version that interprets the record layout differently, or replaying a truncated/partially written recording.

Related errors


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