nautechsystems/nautilus_trader · error
Cannot start bar aggregation: no instrument found for {}
Error message
Cannot start bar aggregation: no instrument found for {} What it means
The DataEngine refuses to start bar aggregation when the instrument for the bar's instrument ID is not present in the cache. Bar aggregation needs the instrument to determine price/size precision, tick size, and bar specification building. The engine treats a missing instrument as a hard precondition, returning anyhow::Error.
Source
Thrown at crates/data/src/engine/mod.rs:4845
}
fn create_bar_aggregator_for_key(
&mut self,
bar_type: BarType,
request_id: Option<UUID4>,
skip_first_non_full_bar: Option<bool>,
) -> anyhow::Result<()> {
let key = bar_aggregator_key(bar_type, request_id);
if self.bar_aggregators.contains_key(&key) {
return Ok(());
}
let instrument = {
let cache = self.cache.borrow();
cache
.instrument(&bar_type.instrument_id())
.ok_or_else(|| {
anyhow::anyhow!(
"Cannot start bar aggregation: no instrument found for {}",
bar_type.instrument_id(),
)
})?
.clone()
};
let aggregator = self.create_bar_aggregator(&instrument, bar_type, skip_first_non_full_bar);
debug_assert_eq!(
aggregator.bar_type(),
key.0,
"aggregator bar type must match its standardized key"
);
self.bar_aggregators
.insert(key, Rc::new(RefCell::new(aggregator)));
Ok(())
}
View on GitHub (pinned to 18893faf8b)
Solutions
- Add the instrument to the cache before subscribing: cache.add_instrument(instrument) or request it via the instrument provider (request_instrument with the matching InstrumentId).
- Verify the bar_type.instrument_id() symbol/venue matches exactly how the instrument was registered (e.g. BTCUSDT.BINANCE vs BTC-USDT.BINANCE).
- Reorder startup so instrument loading/subscription completes before bar subscription.
- Log and inspect cache.instrument(&bar_type.instrument_id()) at the failing point to confirm what is in the cache.
Example fix
// before
engine.subscribe_bars(&bar_type);
// after
if engine.cache().instrument(&bar_type.instrument_id()).is_none() {
engine.request_instrument(bar_type.instrument_id(), None);
}
engine.subscribe_bars(&bar_type); Defensive patterns
Strategy: validation
Validate before calling
if let Some(instrument) = engine.cache().instrument(&bar_type.instrument_id()) {
// safe to subscribe
} else {
engine.request_instrument(bar_type.instrument_id(), None);
} Type guard
fn has_instrument(cache: &Cache, id: &InstrumentId) -> bool {
cache.instrument(id).is_some()
} Prevention
- Always load instruments into the cache before any bar subscriptions.
- Centralize subscription setup in one startup routine ordered after instrument loading.
- Use the instrument provider to request missing instruments on demand.
- Match instrument ID formatting exactly (symbol suffixes, venue codes).
When it happens
Trigger: Calling subscribe_bars (or start_bar_aggregation) with a BarType whose instrument_id was never added to the cache via cache.add_instrument, or subscribing before instrument loading completes.
Common situations: Backtests where instruments were never loaded into the cache; live nodes subscribing to bars for symbols not requested via instrument provider; typos or venue-format mismatches in the instrument ID; subscription racing async instrument load.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Cannot request aggregated bars: one of the aggregators in `b
- Cannot start bar aggregation for {bar_type}
- Cannot setup bar aggregator: no aggregator found for {bar_ty
- Cannot stop bar aggregator: no aggregator to stop for {bar_t
- No live aggregator for continuous future subscription {}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/03ae297d436e3f46.
Report an issue: GitHub.