nautechsystems/nautilus_trader · error
cancel order rejected: {reason}
Error message
cancel order rejected: {reason} What it means
Raised when a cancel-order request is rejected by Bybit (or fails with a confirmed reason) during cancel_order. The adapter emits an OrderCancelRejected event with 'cancel-order-error: {reason}' and then bails with the venue reason.
Source
Thrown at crates/adapters/bybit/src/execution.rs:1978
instrument_id,
Some(client_order_id),
venue_order_id,
)
.await;
if let Err(e) = result {
match classify_cancel_http_failure(&e) {
CommandFailure::VenueRejected(reason) => {
let ts_event = clock.get_time_ns();
emitter.emit_order_cancel_rejected_event(
strategy_id,
instrument_id,
client_order_id,
venue_order_id,
&format!("cancel-order-error: {reason}"),
ts_event,
);
anyhow::bail!("cancel order rejected: {reason}");
}
CommandFailure::NotSent(reason) => {
log::warn!(
"HTTP cancel command failed local validation for {client_order_id}: {reason}"
);
}
CommandFailure::Ambiguous(reason) => {
log::warn!(
"Ambiguous HTTP cancel failure for {client_order_id}, awaiting reconciliation: {reason}"
);
}
}
}
Ok(())
});
return Ok(());View on GitHub (pinned to 18893faf8b)
Solutions
- Check current order status in the cache before cancelling; treat already-filled/cancelled as benign
- Handle rejection reason 'order not exists or too late to cancel' as informational rather than fatal
- Deduplicate cancel requests in strategy logic
- Reconcile order state with the venue after reconnects
Example fix
// before
client.cancel_order(&order)?; // bails if order already filled
// after
if let Some(o) = cache.order(&order.client_order_id()) && o.is_open() {
client.cancel_order(&order)?;
} // else: nothing to cancel Defensive patterns
Strategy: try-catch
Validate before calling
if let Some(o) = cache.order(client_order_id) {
if !o.is_open() {
// already filled/cancelled — nothing to cancel
return Ok(());
}
} Try / catch
match exec_client.cancel_order(&order) {
Err(e) if e.to_string().starts_with("cancel order rejected:") => {
let reason = e.to_string();
if reason.contains("not exists") || reason.contains("too late") {
tracing::info!("order already closed on venue; treating cancel as no-op");
} else {
return Err(e);
}
}
r => r?,
} Prevention
- Check cached order status before cancelling
- Deduplicate cancel requests; reconcile state after reconnects
- Treat 'already filled/cancelled' rejection reasons as benign
- Ensure cancels target orders owned by the same API key/session
When it happens
Trigger: Calling cancel_order when Bybit rejects the cancel — e.g. the order already filled or cancelled, unknown order ID, or the order belongs to another API key.
Common situations: Attempting to cancel an order that just filled; duplicate cancel requests; stale order state after disconnects; cancels submitted for orders from a different session/key.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- submit order rejected: {reason}
- modify order rejected: {reason}
- Either client_order_id or venue_order_id must be provided
- Order cancellation failed: {status}
- {reason}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/7a5a8a363d051808.
Report an issue: GitHub.