nautechsystems/nautilus_trader · warning · OKXInstrumentDefinitionError
instrument is in pre-open state
Error message
instrument is in pre-open state
What it means
A deliberate lookup failure raised when the requested instrument's OKX state is Preopen. Pre-open instruments have incomplete or empty metadata fields (e.g. unset tick size or lot size), so parsing them would produce an invalid instrument; the library refuses and wraps the reason in OKXInstrumentDefinitionError with the symbol.
Source
Thrown at crates/adapters/okx/src/http/client.rs:2620
params.inst_id(symbol);
let params = params.build().map_err(|e| anyhow::anyhow!(e))?;
self.inner
.get_instruments(params)
.await
.map_err(|e| anyhow::anyhow!(e))?
};
let raw_inst = resp
.first()
.ok_or_else(|| InstrumentLookupError::not_found(instrument_id))?;
// Skip pre-open instruments which have incomplete/empty field values
if raw_inst.state == OKXInstrumentStatus::Preopen {
return Err(OKXInstrumentDefinitionError::new(
symbol,
anyhow::anyhow!("instrument is in pre-open state"),
)
.into());
}
let fee_rate_opt = {
let fee_params = GetTradeFeeParams {
inst_type: instrument_type,
uly: None,
inst_family: None,
};
match self.inner.get_trade_fee(fee_params).await {
Ok(rates) => rates.into_iter().next(),
Err(OKXHttpError::MissingCredentials) => {
log::debug!("Missing credentials for fee rates, using None");
None
}
Err(e) => {View on GitHub (pinned to 18893faf8b)
Solutions
- Wait until the instrument's pre-open interval ends and its state becomes Live, then retry the lookup.
- Filter out Preopen-state instruments when enumerating instrument lists (the bulk loader already skips them).
- Handle OKXInstrumentDefinitionError for this symbol gracefully and continue with other instruments.
- Poll periodically until the instrument definition resolves successfully.
Example fix
// before
let instrument = client.request_instrument(symbol)?;
// after
let instrument = match client.request_instrument(symbol) {
Ok(inst) => inst,
Err(e) if e.to_string().contains("pre-open") => {
log::warn!("{symbol} is pre-open; deferring");
return Ok(None);
}
Err(e) => return Err(e.into()),
}; Defensive patterns
Strategy: try-catch
Type guard
fn is_preopen_error(err: &anyhow::Error) -> bool {
err.to_string().contains("pre-open state")
} Try / catch
match client.request_instrument(symbol).await {
Ok(inst) => Ok(Some(inst)),
Err(e) if e.to_string().contains("pre-open") => {
log::info!("{symbol} pre-open; retry later");
Ok(None)
}
Err(e) => Err(e.into()),
} Prevention
- When loading all instruments of a type, filter state == Preopen before parsing.
- Defer newly listed contracts until their pre-open window ends.
- Schedule periodic re-lookup for instruments that were pre-open.
- Treat this error as expected/recoverable, not fatal, in bulk loaders.
When it happens
Trigger: Requesting an instrument definition (request_instrument) whose OKX response has state == Preopen, typically for newly listed contracts (futures/options/swaps) that are listed before trading opens.
Common situations: Subscribing to or loading a brand-new contract on/just after listing day; enumerating all instruments of a type and hitting one in pre-open; stale cached listings referencing not-yet-live contracts.
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
- unsupported instrument type
- instrument update lock poisoned
- option_summary_family_subs mutex poisoned
- Conditional order types must use OKXAlgoOrderType
- Invalid `OrderType` cannot be represented on OKX: {value:?}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/362edf42c0e247b7.
Report an issue: GitHub.