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

  1. 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).
  2. Verify the bar_type.instrument_id() symbol/venue matches exactly how the instrument was registered (e.g. BTCUSDT.BINANCE vs BTC-USDT.BINANCE).
  3. Reorder startup so instrument loading/subscription completes before bar subscription.
  4. 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

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


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