nautechsystems/nautilus_trader · error
no Lighter instrument registered for fill market_index={}
Error message
no Lighter instrument registered for fill market_index={} What it means
Raised while processing fetched fills: a trade arrived from the venue with a market_id that has no registered instrument_id in the adapter's registry, so the fill cannot be mapped to a Nautilus instrument. This is the reverse lookup of error 966 — venue market_index back to a local instrument.
Source
Thrown at crates/adapters/lighter/src/execution.rs:5280
Ok(response) => response,
Err(e) => {
// `{e:#}` preserves the venue's status/body across the
// outer context wrap; `scrub_auth` redacts any `auth=`
// query value the HTTP layer's error included.
log::warn!(
"Lighter get_trades failed (market_id={:?}, account_index={}, cursor={:?}): {}",
query.market_id,
credential.account_index(),
cursor,
scrub_auth(&format!("{e:#}")),
);
return Err(anyhow::Error::new(e).context("failed to fetch Lighter fills"));
}
};
for trade in &response.trades {
let Some(instrument_id) = self.registry.instrument_id(trade.market_id) else {
anyhow::bail!(
"no Lighter instrument registered for fill market_index={}",
trade.market_id,
);
};
let Some(instrument) = self.core.cache().instrument(&instrument_id).cloned() else {
anyhow::bail!("Lighter fill instrument {instrument_id} missing from cache");
};
match parse_ws_fill_report(
trade,
credential.account_index(),
&instrument,
self.core.account_id,
ts_init,
) {
Ok(Some(report)) => {
if cmd.start.is_some_and(|start| report.ts_event < start)
|| cmd.end.is_some_and(|end| report.ts_event > end)View on GitHub (pinned to 18893faf8b)
Solutions
- Refresh/reload instruments so the registry includes the fill's market_id
- Subscribe to all markets the account can trade before fetching fills
- Skip or quarantine the unknown-market fill instead of failing the whole fills sync
- Restart the client to rerun full instrument discovery
Example fix
// before: fetch fills immediately at startup let fills = client.fetch_fills().await?; // after: ensure instruments are loaded first client.request_instruments().await?; // populate registry let fills = client.fetch_fills().await?;
Defensive patterns
Strategy: validation
Validate before calling
// before fetching fills, ensure all tradable markets are registered client.request_instruments().await?; assert!(!client.registry.is_empty(), "instrument registry empty");
Try / catch
match client.fetch_fills().await {
Err(e) if e.to_string().contains("no Lighter instrument registered") => {
client.request_instruments().await?; // refresh registry, then retry
client.fetch_fills().await?;
}
r => r,
} Prevention
- Refresh instrument discovery periodically so new listings are registered
- Load instruments before enabling fills polling at startup
- Subscribe to every market the account can trade, not only actively traded ones
When it happens
Trigger: The fills fetcher received trades for a market the client never registered instruments for — e.g. the account traded a market the adapter did not discover/subscribe to at startup, or a newly listed market appeared between instrument load and the fills fetch.
Common situations: Trading a market added after client startup, fills history covering markets outside the subscribed set, or instrument loading partially failed at startup.
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
- no Lighter market_index for order report instrument {id}
- Active execution intent {intent_id} was not found
- Skipping non-trade execution: {:?}
- Skipping execution without side: {:?}
- Coinbase fill has unknown order side
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/002e1f1a9431dc10.
Report an issue: GitHub.