nautechsystems/nautilus_trader · error · InstrumentLookupError
InstrumentLookupError::not_found(instrument_id)
Error message
InstrumentLookupError::not_found(instrument_id)
What it means
Raised by `lazy_load_instrument` after fetching instrument data from Derive when no returned instrument matches the requested instrument_id. It wraps `InstrumentLookupError::not_found`, meaning the exchange query succeeded but the specific instrument does not exist (or is not tradable/listed).
Source
Thrown at crates/adapters/derive/src/data.rs:569
instruments: Arc<AtomicMap<InstrumentId, InstrumentAny>>,
instrument_id: InstrumentId,
include_expired: bool,
) -> anyhow::Result<()> {
let currency = currency_from_instrument_id(&instrument_id)?;
let definitions = fetch_instrument_definitions(&http_client, currency, include_expired)
.await
.with_context(|| format!("failed to lazy-load Derive instruments for {currency}"))?;
let mut found = false;
for instrument in parse_instrument_definitions(definitions) {
if instrument.id() == instrument_id {
found = true;
}
cache_instrument(&instruments, &instrument);
}
if !found {
anyhow::bail!(InstrumentLookupError::not_found(instrument_id));
}
Ok(())
}
fn ws_handle(&self) -> DeriveWebSocketSubscriptionHandle {
self.ws_client.subscription_handle()
}
fn subscription_lifecycle(&self) -> SubscriptionLifecycle {
SubscriptionLifecycle {
registry: Arc::clone(&self.channel_subscriptions),
lock: Arc::clone(&self.subscription_lock),
dispatch: SubscriptionDispatchState {
active_book_delta_channels: Arc::clone(&self.active_book_delta_channels),
active_book_depth10_channels: Arc::clone(&self.active_book_depth10_channels),
active_ticker_channels: Arc::clone(&self.active_ticker_channels),
active_quote_subs: Arc::clone(&self.active_quote_subs),View on GitHub (pinned to 18893faf8b)
Solutions
- Verify the InstrumentId symbol exists and is active on Derive (check symbol format and case).
- Confirm the instrument is not expired/delisted; use a current instrument.
- Ensure configured currencies/instrument-type filters cover the requested instrument.
- Add the instrument explicitly via request_instruments and check the response before subscribing.
Example fix
null
Defensive patterns
Strategy: try-catch
Validate before calling
// verify instrument exists on Derive before lazy load let exists = derive_rest_instrument_exists(&symbol, ¤cy)?;
Try / catch
if let Err(e) = lazy_load_instrument(instrument_id).await {
log::warn!("{e}; skipping subscription for {instrument_id}");
return Ok(()); // degrade gracefully instead of failing the subscribe
} Prevention
- Check instrument is active and not expired on Derive.
- Keep configured currencies/instrument-type filters in sync with traded instruments.
- Validate symbol format (venue, base-quote, kind suffix) before requesting.
When it happens
Trigger: Auto-loading (`auto_load_missing_instruments: true`) an InstrumentId during prepare_subscribe where lazy_load_instrument queries Derive for the instrument type/currency but the matching instrument is absent from the response.
Common situations: Requesting delisted or expired instruments; misspelled or wrong-format symbols; requesting an instrument whose underlying currency isn't covered by the query used; instruments on a different Derive sub-market.
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
- Instrument {instrument_id} not found and `auto_load_missing_
- Derive only supports L2_MBP order book deltas
- Derive only supports L2_MBP order book depth
- invalid Derive subscription channel `{channel}`
- Derive execution startup teardown failed: {teardown_error}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/06289b0c11d8305c.
Report an issue: GitHub.