nautechsystems/nautilus_trader · error
failed to fetch Lighter fills
Error message
failed to fetch Lighter fills
What it means
When fetching fills (trade history) from Lighter via get_trades, a failed HTTP/API call is wrapped as 'failed to fetch Lighter fills'. The request parameters (market_id, account_index, cursor) are logged with auth scrubbed before this error is raised, so callers get pagination context plus the underlying cause.
Source
Thrown at crates/adapters/lighter/src/execution.rs:5274
trade_type: None,
limit: LIGHTER_REST_PAGE_SIZE,
aggregate: None,
});
let response = match self.http_client.get_trades(&query).await {
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,View on GitHub (pinned to 18893faf8b)
Solutions
- Read the scrubbed inner error ({e:#}) for the HTTP status and Lighter error code.
- Reset pagination and re-fetch from the first page if the cursor was stale/invalid.
- Refresh or re-verify Lighter API credentials; auth failures surface here.
- Retry with backoff on 429/5xx; fills fetch is safe to re-run since it is read-only.
Example fix
// before let trades = http_client.get_trades(query).await?; // Err -> failed to fetch Lighter fills // after let trades = backoff(|| http_client.get_trades(reset_cursor_if_stale(query)).await).await?;
Defensive patterns
Strategy: retry
Validate before calling
// validate cursor and market id before fetching fills assert!(query.market_id.is_some() || query.fetch_all);
Try / catch
match client.generate_order_status_reports(...).await {
Err(e) if format!("{e:#}").contains("failed to fetch Lighter fills") => {
// reset cursor to None and retry with backoff
}
r => r?,
} Prevention
- Reset stale cursors to the first page on fetch failure
- Refresh Lighter credentials before long reconciliation jobs
- Back off on 429/5xx; the fetch is read-only and safe to re-run
- Log with auth scrubbing to share errors safely
When it happens
Trigger: generate_order_status_reports / fill generation path calls the Lighter get_trades endpoint with a market_id/account_index/cursor and the request returns Err — network failure, 4xx/5xx, auth rejection, or rate limit.
Common situations: Backfilling fills after a disconnect, paging through fills with a stale or invalid cursor, expired Lighter API credentials, or venue API downtime during report reconciliation.
Understand the failure class
Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.
Related errors
- Lighter query_order requires credentials
- Modify order failed: {e}
- Skipping non-trade execution: {:?}
- Skipping execution without side: {:?}
- Either client_order_id or venue_order_id is required
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/8a4449e2f8f0eeda.
Report an issue: GitHub.