nautechsystems/nautilus_trader · error
Instrument {instrument_id} is expired and no longer availabl
Error message
Instrument {instrument_id} is expired and no longer available for market data requests What it means
The Polymarket data client rejects historical/request-style market data calls (request_book_snapshot, request_trades) when the target instrument is expired and not reported open. Unlike live subscriptions, this path first resolves the instrument and then validates it is still tradeable/open before issuing the request. It prevents wasted REST calls against closed markets.
Source
Thrown at crates/adapters/polymarket/src/data/mod.rs:371
"Instrument {instrument_id} is expired and no longer available for live subscription"
);
}
Ok(())
}
fn ensure_market_data_request_allowed(
&self,
instrument_id: InstrumentId,
) -> anyhow::Result<InstrumentAny> {
let loaded = self.instruments.load();
let instrument = loaded
.get(&instrument_id)
.ok_or_else(|| InstrumentLookupError::not_found(instrument_id))?
.clone();
if is_instrument_expired_and_not_reported_open(&instrument, self.clock.get_time_ns()) {
anyhow::bail!(
"Instrument {instrument_id} is expired and no longer available for market data requests"
);
}
Ok(instrument)
}
fn add_live_subscription_intent(
&self,
instrument_id: InstrumentId,
subscriptions: &Arc<AtomicSet<InstrumentId>>,
) -> bool {
self.add_live_subscription_intent_with_state(instrument_id, subscriptions, || {})
}
fn add_delta_subscription_intent(&self, instrument_id: InstrumentId) -> bool {
self.add_live_subscription_intent_with_state(instrument_id, &self.active_delta_subs, || {
if self.config.compute_effective_deltas {View on GitHub (pinned to 18893faf8b)
Solutions
- Verify the market is open on Polymarket before issuing historical data requests.
- Filter the request list to instruments whose end date is in the future.
- If historical data for an expired market is needed, use a source that supports closed-market history rather than the live adapter's request path.
- Refresh cached instrument metadata if the expiry recorded locally is stale or wrong.
Example fix
// before
let book = client.request_book_snapshot(instrument_id)?;
// after
if instrument.expiration_ts_ns() > clock.get_time_ns() {
let book = client.request_book_snapshot(instrument_id)?;
} else {
log::warn!("market {instrument_id} expired; skipping snapshot request");
} Defensive patterns
Strategy: validation
Validate before calling
if instrument.expiration_ns() <= clock.get_time_ns().as_u64() {
return Ok(None); // skip request for expired market
} Try / catch
match client.request_book_snapshot(instrument_id) {
Ok(book) => Some(book),
Err(e) if e.to_string().contains("expired") => { log::warn!("expired market {instrument_id}"); None }
Err(e) => return Err(e),
} Prevention
- Filter scheduled data pulls by market end date.
- Drop finished markets from backfill job lists.
When it happens
Trigger: Calling request_book_snapshot or request_trades for an InstrumentId whose cached instrument passes is_instrument_expired_and_not_reported_open at clock.get_time_ns().
Common situations: Backfill jobs or warm-up code requesting snapshots for markets that expired since the config was written; scheduled data pulls that keep running past a market's end date.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Instrument {instrument_id} is expired and no longer availabl
- unmapped_in_scope_message("open order", instrument_id, Some(
- unmapped_in_scope_message("position", instrument_id, None, c
- Unknown IB historical tick type: {value}
- Subscription error: {e:?}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/b77bcc3a712d4402.
Report an issue: GitHub.