{"record":{"id":"99b5c8951a61e339","repo":"nautechsystems/nautilus_trader","slug":"order-quantity-must-be-at-least-1-contract","errorCode":null,"errorMessage":"Order quantity must be at least 1 contract","messagePattern":"Order quantity must be at least 1 contract","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/architect_ax/src/common/parse.rs","lineNumber":207,"sourceCode":"/// - The quantity is zero.\npub fn quantity_to_contracts(quantity: Quantity) -> anyhow::Result<u64> {\n    let raw = quantity.raw;\n    let scale = 10_u64.pow(FIXED_PRECISION as u32) as QuantityRaw;\n\n    // AX requires whole contract quantities\n    if !raw.is_multiple_of(scale) {\n        anyhow::bail!(\n            \"AX requires whole contract quantities, was {}\",\n            quantity.as_f64()\n        );\n    }\n\n    // QuantityRaw is u128 under the `high-precision` feature and u64 otherwise,\n    // so the narrowing cast is conditional on the active feature set.\n    #[allow(clippy::unnecessary_cast)]\n    let contracts = (raw / scale) as u64;\n    if contracts == 0 {\n        anyhow::bail!(\"Order quantity must be at least 1 contract\");\n    }\n    Ok(contracts)\n}\n\n/// Converts a [`ClientOrderId`] to a deterministic AX `cid` in the non-negative `int64` range.\n///\n/// Inbound WebSocket `cid` values remain `u64` because venue messages can exceed `int64`.\n#[must_use]\npub fn client_order_id_to_cid(client_order_id: &ClientOrderId) -> u64 {\n    CID_HASHER.hash_one(client_order_id.inner()) & i64::MAX as u64\n}\n\n/// Creates a [`ClientOrderId`] from a cid value.\n///\n/// Used when we receive an order with a cid but cannot resolve it to the\n/// original ClientOrderId (e.g., after restart when in-memory mapping is lost).\n#[must_use]\npub fn cid_to_client_order_id(cid: u64) -> ClientOrderId {","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/architect_ax/src/common/parse.rs#L189-L225","documentation":"After dividing out the fixed-precision scale, `quantity_to_contracts` rejects a resulting contract count of 0. This catches quantities that are whole but smaller than one contract (e.g. quantity 0, or a fractional value that rounded contextually). AX orders must be at least 1 contract.","triggerScenarios":"submit_order or modify_order called with quantity 0, or any quantity in (0, 1) contracts, through the AX execution client.","commonSituations":"Strategies computing near-zero target deltas and emitting 0-size orders; min-quantity guard missing before submit; misconfigured size_increment.","solutions":["Check quantity >= instrument min_quantity (and >= 1 contract) before submitting","Skip no-op rebalances where the target delta rounds to zero contracts","Correct strategy sizing logic producing zero/negative order sizes"],"exampleFix":"// before\nif target_delta != 0.0 { submit(target_delta) }\n// after\nlet contracts = target_delta.floor();\nif contracts >= 1.0 { submit(Quantity::new(contracts, 0)) }","handlingStrategy":"validation","validationCode":"if order.quantity().as_f64() < 1.0 {\n    return; // skip no-op order\n}","typeGuard":null,"tryCatchPattern":"match quantity_to_contracts(qty) {\n    Ok(n) if n >= 1 => submit(n),\n    Ok(_) | Err(_) => log::debug!(\"quantity below 1 contract, not submitting\"),\n}","preventionTips":["Check instrument.min_quantity before every submit","Ignore rebalance deltas smaller than one contract","Validate size_increment configuration on instrument load"],"tags":["rust","adapter","quantity","validation","orders"],"backgroundTag":"value-out-of-range","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}