nautechsystems/nautilus_trader · error
Missing `exchange` for record: {e}
Error message
Missing `exchange` for record: {e} What it means
For GLBX.MDP3 publisher records when `use_exchange_as_venue` is enabled, the loader calls `rec.exchange()` to derive the venue from the record's exchange code. If the record carries no exchange field the map_err wraps the failure as this error.
Source
Thrown at crates/adapters/databento/src/loader.rs:282
let result: anyhow::Result<Option<InstrumentAny>> = (|| {
let record = dbn::RecordRef::from(rec);
let msg = record
.get::<InstrumentDefMsg>()
.ok_or_else(|| anyhow::anyhow!("Failed to decode InstrumentDefMsg"))?;
let raw_symbol = rec
.raw_symbol()
.map_err(|e| anyhow::anyhow!("Error decoding `raw_symbol`: {e}"))?;
let symbol = Symbol::from(raw_symbol);
let publisher = rec
.hd
.publisher()
.map_err(|e| anyhow::anyhow!("Invalid `publisher` for record: {e}"))?;
let venue = match publisher {
Publisher::GlbxMdp3Glbx if use_exchange_as_venue => {
let exchange = rec.exchange().map_err(|e| {
anyhow::anyhow!("Missing `exchange` for record: {e}")
})?;
let venue = Venue::from_code(exchange).map_err(|e| {
anyhow::anyhow!("Venue not found for exchange {exchange}: {e}")
})?;
self.symbol_venue_map.insert(symbol, venue);
venue
}
_ => *self
.publisher_venue_map
.get(&msg.hd.publisher_id)
.ok_or_else(|| {
anyhow::anyhow!(
"Venue not found for publisher_id {}",
msg.hd.publisher_id
)
})?,
};
let instrument_id = InstrumentId::new(symbol, venue);View on GitHub (pinned to 18893faf8b)
Solutions
- Set `use_exchange_as_venue = false` so the venue comes from the publisher map instead of the exchange field
- Verify the dataset/record type actually carries an exchange field (check schema version)
- Update the `dbn` crate and re-export the data, since newer schemas populate exchange consistently
- Filter out records with empty exchange before feeding the loader
Example fix
// before let loader = DatabentoInstrumentLoader::new(publisher_venue_map, true); // after let loader = DatabentoInstrumentLoader::new(publisher_venue_map, false); // fall back to publisher_id venue mapping
Defensive patterns
Strategy: validation
Validate before calling
// only use exchange-as-venue for GLBX data whose records carry exchange codes let use_exchange_as_venue = dataset == "GLBX.L3" && schema_supports_exchange(schema);
Try / catch
match loader.load_instruments(file) {
Ok(i) => i,
Err(e) if e.to_string().contains("Missing `exchange`") => {
// retry with publisher-based venue mapping
DatabentoInstrumentLoader::new(publisher_venue_map, false).load_instruments(file)
}
Err(e) => return Err(e),
} Prevention
- Enable `use_exchange_as_venue` only for GLBX.MDP3 datasets
- Confirm the schema version populates the exchange field
- Prefer publisher-based venue mapping unless per-exchange venues are required
When it happens
Trigger: Reading definition records with `use_exchange_as_venue = true` where a GLBX.MDP3 record lacks the exchange field (e.g. certain instrument definition schemas or record types that omit exchange).
Common situations: Loading older GLBX definition datasets where exchange was not populated, or feeding non-GLBX records mislabeled with the GlbxMdp3Glbx publisher.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- Missing exchange in record: {e}
- Invalid `publisher` for record: {e}
- AX whoami account {} supplied no fee rates
- DEX {} does not have initialize event set.
- Missing fee in topic3 when parsing pool created event
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/3e201e208babdedc.
Report an issue: GitHub.