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 an order detail request
What it means
request_order_detail requires exactly one order identifier: the match on (client_order_id, venue_order_id) accepts (Some, None) or (None, Some); any other combination — both None or both Some — bails. OKX's order-detail endpoint takes either clOrdId or ordId, not both, and the adapter maps exactly one.
Source
Thrown at crates/adapters/okx/src/http/client.rs:4375
async fn request_order_status_report_by_identifier(
&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 = GetOrderParamsBuilder::default();
params_builder.inst_id(instrument_id.symbol.inner().to_string());
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 an order detail request"
),
}
let params = params_builder
.build()
.map_err(|e| anyhow::anyhow!("Failed to build order detail params: {e}"))?;
let orders = match self.inner.get_order(params).await {
Ok(orders) => orders,
Err(e) if e.is_order_not_found() => return Ok(None),
Err(e) => return Err(e.into()),
};
let order = match orders.as_slice() {
[] => return Ok(None),
[order] => order,
_ => anyhow::bail!(
"Order detail returned {} records for one identifier",
orders.len(),View on GitHub (pinned to 18893faf8b)
Solutions
- Pass exactly one of client_order_id or venue_order_id — prefer venue_order_id (ordId) if known
- Clear one identifier before the call when both are present
- Ensure upstream identifier resolution succeeds before invoking the detail request
Example fix
// before client.request_order_detail(instrument_id, Some(coid), Some(oid)).await?; // after client.request_order_detail(instrument_id, None, Some(oid)).await?;
Defensive patterns
Strategy: validation
Validate before calling
match (client_order_id, venue_order_id) {
(Some(_), None) | (None, Some(_)) => {}
_ => return Err(anyhow::anyhow!("pass exactly one order identifier")),
} Type guard
fn single_identifier(c: Option<ClientOrderId>, v: Option<VenueOrderId>) -> bool {
matches!((c.is_some(), v.is_some()), (true, false) | (false, true))
} Try / catch
match client.request_order_detail(instrument_id, coid, void).await {
Ok(Some(report)) => { /* use */ }
Ok(None) => { /* order not found */ }
Err(e) => log::error!("order detail failed: {e}"),
} Prevention
- Pass exactly one identifier; prefer venue_order_id when known
- Never pass both identifiers 'for safety' — the API rejects it
- Ensure fallback logic always resolves at least one ID before calling
When it happens
Trigger: Calling the OKX HTTP client's order-detail method with both identifiers None, or both Some (ambiguous request).
Common situations: Report generation code that opportunistically fills both IDs (venue rejects the call); fallback logic that neither ID resolved; refactored callers passing both 'to be safe'.
Related errors
- Order detail instrument mismatch for {instrument_id}: return
- Order detail venue order ID mismatch for {venue_order_id}: r
- Failed to build order detail params: {e}
- {FAILED}: {e}
- {FAILED}: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/d28eebff4e9a026a.
Report an issue: GitHub.