nautechsystems/nautilus_trader · error
Failed to build cancel params
Error message
Failed to build cancel params: {e} What it means
The cancel-order flow builds `CancelOrderParams` through a builder that validates the request. When `build()` rejects the field combination (e.g. missing transaction id / client order id), the adapter raises this anyhow error without sending the HTTP request. It signals the cancel parameters are structurally invalid, not that the venue rejected the cancel.
Solutions
- Read the inner `{e}` message to see the builder's complaint.
- Ensure at least one of `txid` (venue order id) or `cl_ord_id` is a non-empty string before calling cancel.
- Verify the order reached the venue (has a `venue_order_id`) before issuing cancels; skip cancel for unacknowledged orders.
- Log the builder inputs when this occurs to spot empty/None identifiers upstream.
Example fix
// before
let cl_ord_id: Option<String> = order.client_order_id(); // None for unacknowledged order
// after
if order.venue_order_id().is_none() { return Ok(()); } // nothing to cancel
builder.txid(order.venue_order_id().unwrap().to_string()); Defensive patterns
Strategy: validation
Validate before calling
fn validate_cancel(venue_order_id: Option<&String>, cl_ord_id: Option<&String>) -> Result<(), String> {
let has_txid = venue_order_id.map_or(false, |s| !s.is_empty());
let has_cl = cl_ord_id.map_or(false, |s| !s.is_empty());
if has_txid || has_cl { Ok(()) } else { Err("cancel requires txid or cl_ord_id".into()) }
} Type guard
fn has_identifier(id: &Option<String>) -> bool {
id.as_deref().map_or(false, |s| !s.is_empty())
} Try / catch
match client.cancel_order(req).await {
Ok(_) => (),
Err(e) if e.to_string().contains("Failed to build cancel params") => {
log::warn!("skipping cancel, invalid params: {e}");
}
Err(e) => return Err(e),
} Prevention
- Only cancel orders that have been acknowledged by the venue
- Prefer the venue order id over client order id for cancels
- Check for empty-string identifiers before constructing cancel requests
When it happens
Trigger: Calling cancel-order with neither `txid` nor `cl_ord_id` set, or with values the builder considers invalid (empty strings, both identifiers conflicting per builder rules).
Common situations: Cancelling from a code path where the order was never acknowledged so no venue order id exists; empty string client order IDs passed through from order manager state; refactor changed which identifier branch populates the builder.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Failed to build amend order params
- Failed to build order params
- batch_add requires at least one order
- Conditional order type
- Failed to build edit order params
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/5ad5eb6fdeeb693e.
Report an issue: GitHub.
Appendix: source
Thrown at crates/adapters/kraken/src/http/spot/client.rs:2957
let txid = venue_order_id.as_ref().map(|id| id.to_string());
let cl_ord_id = client_order_id.as_ref().map(truncate_cl_ord_id);
if txid.is_none() && cl_ord_id.is_none() {
anyhow::bail!("Either client_order_id or venue_order_id must be provided");
}
// Prefer txid (venue identifier) since Kraken always knows it.
// cl_ord_id may not be known to Kraken for reconciled orders.
let mut builder = KrakenSpotCancelOrderParamsBuilder::default();
if let Some(ref id) = txid {
builder.txid(id.clone());
} else if let Some(ref id) = cl_ord_id {
builder.cl_ord_id(id.clone());
}
let params = builder
.build()
.map_err(|e| anyhow::anyhow!("Failed to build cancel params: {e}"))?;
self.inner.cancel_order(¶ms).await?;
Ok(())
}
/// Cancels multiple orders on the Kraken Spot exchange (batched, max 50 per request).
pub async fn cancel_orders_batch(
&self,
venue_order_ids: Vec<VenueOrderId>,
) -> anyhow::Result<i32> {
if venue_order_ids.is_empty() {
return Ok(0);
}
let mut total_cancelled = 0;
for chunk in venue_order_ids.chunks(BATCH_CANCEL_LIMIT) {View on GitHub (pinned to 18893faf8b)