nautechsystems/nautilus_trader · error
Failed to decode instrument {instrument_id}: {e}
Error message
Failed to decode instrument {instrument_id}: {e} What it means
`get_range_instruments` (used by `seed_price_precision_if_needed`) fetches instrument definitions from Databento and decodes each into a Nautilus `InstrumentDef`. When `decode_instrument_def_msg` fails for a specific instrument, the error is wrapped with the instrument_id and propagated, aborting the whole definitions request rather than skipping the instrument.
Source
Thrown at crates/adapters/databento/src/historical.rs:329
&record,
&mut metadata_cache,
&self.publisher_venue_map,
&sym_map,
)?;
if self.use_exchange_as_venue && instrument_id.venue == Venue::GLBX() {
let exchange = msg
.exchange()
.map_err(|e| anyhow::anyhow!("Missing exchange in record: {e}"))?;
let venue = Venue::from_code(exchange)
.map_err(|e| anyhow::anyhow!("Venue not found for exchange {exchange}: {e}"))?;
instrument_id.venue = venue;
}
match decode_instrument_def_msg(msg, instrument_id, None, None) {
Ok(Some(instrument)) => instruments.push(instrument),
Ok(None) => {} // Decoder logged a warning for the unsupported class
Err(e) => anyhow::bail!("Failed to decode instrument {instrument_id}: {e}"),
}
}
for instrument in &instruments {
self.price_precisions
.insert(instrument.id().symbol, instrument.price_precision());
}
Ok(instruments)
}
/// Fetches quote ticks for the given parameters.
///
/// # Errors
///
/// Returns an error if the API request or data processing fails.
pub async fn get_range_quotes(
&self,View on GitHub (pinned to 18893faf8b)
Solutions
- Read the wrapped inner error and instrument_id to identify the failing record; request that definition alone to inspect it.
- Remove or pre-validate the offending symbol from the request.
- If the instrument class is unsupported, ensure the decoder is expected to skip (Ok(None)) — check which check returned Err instead.
- Wrap the seeding call so a failing instrument can be skipped instead of failing the whole data request.
Example fix
// before
match decode_instrument_def_msg(msg, instrument_id, None, None)? { ... }
// after
match decode_instrument_def_msg(msg, instrument_id, None, None) {
Ok(Some(i)) => instruments.push(i),
Ok(None) => {}
Err(e) => { log::warn!("skipping {instrument_id}: {e}"); continue; }
} Defensive patterns
Strategy: try-catch
Try / catch
match get_range_instruments(...).await {
Ok(defs) => defs,
Err(e) => {
// e contains "Failed to decode instrument <id>: <cause>"
let id = extract_instrument_id(&e.to_string());
log::warn!("skipping undecodable instrument {id}: {e}");
Vec::new()
}
} Prevention
- Request definitions for symbols individually or in small batches so one bad record doesn't poison the batch.
- Keep the adapter and dbn crate versions in sync.
- Log the full anyhow chain to see the inner decode cause.
When it happens
Trigger: Calling a historical data range method that needs price precision seeding, where one of the returned definition records fails to decode (e.g. undefined required price/timestamp/multiplier, or unsupported instrument class returning Err).
Common situations: Requesting data for a symbol batch where a single broken/unusual definition poisons the entire call; asset classes whose definition fields don't match the decoder's expectations; Databento schema changes.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Missing required price for `{field_name}`
- Invalid negative quantity: {value}
- Missing required timestamp for `{field_name}`
- Invalid negative multiplier: {v}
- Invalid data element not `QuoteTick`, was {data:?}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/2b52e3954d1b7c35.
Report an issue: GitHub.