nautechsystems/nautilus_trader · error

Instrument {symbol} not in cache

Error message

Instrument {symbol} not in cache

What it means

instrument_from_cache looks up the adapter-local instrument cache by Binance symbol; when absent it errors. The HTTP client needs the InstrumentAny to map prices/quantities to correct precision, so requests like trades/bars/cancel-replace fail without it.

Source

Thrown at crates/adapters/binance/src/spot/http/client.rs:2601

    /// Generates a timestamp for initialization.
    fn generate_ts_init(&self) -> UnixNanos {
        self.clock.get_time_ns()
    }

    fn command_validation_error(message: impl Into<String>) -> anyhow::Error {
        anyhow::anyhow!(BinanceSpotHttpError::ValidationError(message.into()))
    }

    fn response_parse_error(message: impl Into<String>) -> anyhow::Error {
        anyhow::anyhow!(BinanceSpotHttpError::ResponseParseError(message.into()))
    }

    /// Retrieves an instrument from the cache.
    fn instrument_from_cache(&self, symbol: Ustr) -> anyhow::Result<InstrumentAny> {
        self.instruments_cache
            .get_cloned(&symbol)
            .ok_or_else(|| anyhow::anyhow!("Instrument {symbol} not in cache"))
    }

    /// Caches multiple instruments.
    pub fn cache_instruments(&self, instruments: Vec<InstrumentAny>) {
        self.instruments_cache.rcu(move |cache| {
            for instrument in &instruments {
                cache.insert(instrument.raw_symbol().inner(), instrument.clone());
            }
        });
    }

    /// Replaces the complete instrument cache.
    pub fn replace_instruments(&self, instruments: &[InstrumentAny]) {
        let cache = instruments
            .iter()
            .map(|instrument| (instrument.raw_symbol().inner(), instrument.clone()))
            .collect();
        self.instruments_cache.store(cache);

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Include the symbol in InstrumentProviderConfig load_ids or set load_all=True
  2. Ensure instruments are initialized (venue 'connect'/instrument provider load) before requesting data
  3. Verify the exact Binance symbol string (uppercase, no separators)
  4. Check for request races in your actor's on_start ordering

Example fix

// before
config = BinanceDataClientConfig(...)  # no load_ids -> symbol missing
# after
config = BinanceDataClientConfig(instrument_provider=InstrumentProviderConfig(load_ids=["BINANCE.BTCUSDT"]))
Defensive patterns

Strategy: validation

Validate before calling

if client.get_instrument(&symbol).is_none() {
    return Err(format!("symbol {symbol} not loaded; add to instrument provider load_ids"));
}

Type guard

fn instrument_loaded(cache: &Cache, symbol: Ustr) -> bool { cache.instrument(&InstrumentId::from(format!("{symbol}.BINANCE"))).is_some() }

Try / catch

match result { Err(e) if e.to_string().contains("not in cache") => load_instruments_then_retry(), Err(e) => return Err(e), Ok(i) => Ok(i) }

Prevention

When it happens

Trigger: Requesting historical trades, bars, or issuing commands for a symbol that was never loaded — e.g. subscribing/requests made before instruments are initialized, or a symbol not part of the configured instrument provider.

Common situations: Strategy referencing symbols not in the configured load_all/load_ids filter; a race where data requests fire before instrument warm-up completes; typo in symbol casing (Binance symbols are uppercase, e.g. BTCUSDT).

Understand the failure class

Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.

Related errors


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