nautechsystems/nautilus_trader · error
Exactly one of client_order_id or venue_order_id is required
Error message
Exactly one of client_order_id or venue_order_id is required for a spread order detail request
What it means
When requesting a single spread order's details from OKX, exactly one identifier must be supplied: either the client order ID (sent as `clOrdId`) or the venue order ID (sent as `ordId`). Passing both, or neither, is ambiguous/invalid, so the client bails before building the request.
Source
Thrown at crates/adapters/okx/src/http/client.rs:7049
pub(crate) async fn request_spread_order_status_report(
&self,
account_id: AccountId,
instrument_id: InstrumentId,
client_order_id: Option<ClientOrderId>,
venue_order_id: Option<VenueOrderId>,
) -> anyhow::Result<Option<OrderStatusReport>> {
let instrument = self.instrument_from_cache(instrument_id.symbol.inner())?;
let mut params_builder = GetSpreadOrderParamsBuilder::default();
match (client_order_id, venue_order_id) {
(Some(client_order_id), None) => {
params_builder.cl_ord_id(client_order_id.as_str().to_string());
}
(None, Some(venue_order_id)) => {
params_builder.ord_id(venue_order_id.as_str().to_string());
}
_ => anyhow::bail!(
"Exactly one of client_order_id or venue_order_id is required for a spread order detail request"
),
}
let params = params_builder
.build()
.map_err(|e| anyhow::anyhow!("Failed to build spread order detail params: {e}"))?;
let orders = match self.inner.get_spread_order(params).await {
Ok(orders) => orders,
Err(e) if e.is_order_not_found() => return Ok(None),
Err(e) => return Err(e.into()),
};
let Some(order) = orders.into_iter().next() else {
return Ok(None);
};
let ts_init = self.generate_ts_init();
let report = parse_spread_order_status_report(
&order,View on GitHub (pinned to 18893faf8b)
Solutions
- Pass exactly one of `client_order_id` or `venue_order_id` — prefer `venue_order_id` if you have it from a prior report.
- If both are available, drop the client order ID and use the venue order ID.
- If neither is known, first query order status reports to obtain an order ID.
Example fix
// before client.request_spread_order_detail(Some(&cl_ord_id), Some(&venue_ord_id)).await?; // after client.request_spread_order_detail(None, Some(&venue_ord_id)).await?;
Defensive patterns
Strategy: validation
Validate before calling
let n = client_order_id.is_some() as u8 + venue_order_id.is_some() as u8;
if n != 1 {
return Err(anyhow::anyhow!("pass exactly one of client_order_id or venue_order_id"));
} Prevention
- Prefer venue_order_id when both IDs are known from prior reports.
- Never populate both Option fields from generic report-building code.
- Obtain an order ID via order status reports when neither is available.
When it happens
Trigger: Calling the spread order detail query with `client_order_id` and `venue_order_id` both `Some`, or both `None`.
Common situations: Passing an Nautilus `ClientOrderId` together with a `VenueOrderId` populated by reconciliation; calling the query from generic report code where neither ID was set.
Related errors
- instrument_type or instrument_id required for algo order que
- Invalid time range: start={s:?} end={e:?}
- Failed to build spread order detail params: {e}
- `tick_sz` is empty for {}
- `lot_sz` is empty for {}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/5715093ab7adde25.
Report an issue: GitHub.