{"record":{"id":"4ce4821a8db55d72","repo":"nautechsystems/nautilus_trader","slug":"failed-to-resolve-positive-quantity-for-current-or","errorCode":null,"errorMessage":"failed to resolve positive quantity for current order {} (order_type={:?}, persistence_type={:?}, price_size={}, bsp_liability={}, size_matched={}, size_remaining={}, size_cancelled={}, size_lapsed={}, size_voided={})","messagePattern":"failed to resolve positive quantity for current order (.+?) \\(order_type=(.+?), persistence_type=(.+?), price_size=(.+?), bsp_liability=(.+?), size_matched=(.+?), size_remaining=(.+?), size_cancelled=(.+?), size_lapsed=(.+?), size_voided=(.+?)\\)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/betfair/src/http/parse.rs","lineNumber":85,"sourceCode":"        OrderStatus::Voided\n    } else {\n        resolve_order_status(order.status, size_matched, size_closed)\n    };\n\n    // Prefer lifecycle sum when price_size.size is zero. Use bsp_liability for\n    // on-close orders that report liability without stake/size.\n    let total_size = order.price_size.size;\n    let lifecycle_qty = size_matched + size_remaining + size_cancelled + size_lapsed + size_voided;\n    let qty = if total_size > Decimal::ZERO {\n        total_size\n    } else if lifecycle_qty > Decimal::ZERO {\n        lifecycle_qty\n    } else if uses_liability_based_quantity(order) && order.bsp_liability > Decimal::ZERO {\n        order.bsp_liability\n    } else {\n        Decimal::ZERO\n    };\n    anyhow::ensure!(\n        qty > Decimal::ZERO,\n        \"failed to resolve positive quantity for current order {} \\\n         (order_type={:?}, persistence_type={:?}, price_size={}, bsp_liability={}, \\\n         size_matched={}, size_remaining={}, size_cancelled={}, size_lapsed={}, size_voided={})\",\n        order.bet_id,\n        order.order_type,\n        order.persistence_type,\n        order.price_size.size,\n        order.bsp_liability,\n        size_matched,\n        size_remaining,\n        size_cancelled,\n        size_lapsed,\n        size_voided,\n    );\n    let quantity = parse_betfair_quantity(qty)?;\n    let filled_qty = parse_betfair_quantity(size_matched)?;\n","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/betfair/src/http/parse.rs#L67-L103","documentation":"When parsing a Betfair current-order report, no positive quantity could be derived from the order's fields (order type, price/size, BSP liability, matched/remaining/cancelled/lapsed/voided sizes). The library throws via anyhow::ensure! because downstream execution/reconciliation logic requires a strictly positive quantity.","triggerScenarios":"query_order or fetch_order_status_reports_snapshot_http receives a current order whose resolved lifecycle quantity is zero or negative and which is not a liability-based order (e.g. market-on-close) with bsp_liability > 0.","commonSituations":"Fully voided or fully lapsed orders without recorded fills; placeholder BET_DELAY-style orders with size fields all zero; orders whose order_type the quantity resolver does not recognize; Betfair returning reports for orders cancelled before matching.","solutions":["Skip orders with all-zero size fields instead of querying their status, or filter them in the caller.","Check the order's order_type; ensure SP/liability orders carry bsp_liability > 0 in the report.","Log the full order payload and verify Betfair returned real values (no missing size fields).","If this occurs for legitimate states, handle a zero quantity as a terminal/no-op order in reconciliation before calling parse."],"exampleFix":"// before\nlet report = client.query_order(&bet_id).await?;\n// after\nlet report = client.query_order(&bet_id).await?;\nif report.size_cancelled + report.size_lapsed + report.size_voided > Decimal::ZERO\n    && report.size_matched == Decimal::ZERO {\n    return Ok(None); // never-matched terminal order has no resolvable quantity\n}","handlingStrategy":"validation","validationCode":"fn has_resolvable_qty(o: &CurrentOrder) -> bool {\n    o.bsp_liability > Decimal::ZERO\n        || o.size_matched > Decimal::ZERO\n        || o.size_remaining > Decimal::ZERO\n}","typeGuard":null,"tryCatchPattern":"match client.query_order(&bet_id).await {\n    Ok(r) => r,\n    Err(e) if e.to_string().contains(\"failed to resolve positive quantity\") => {\n        log::warn!(\"order {bet_id} has no resolvable quantity; treating as terminal\");\n        Default::default()\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Skip orders with all-zero size fields before querying their status.","Reconcile never-matched cancelled/lapsed orders as terminal without quantity resolution.","Log raw Betfair order payloads to detect SP orders missing bsp_liability."],"tags":["parsing","betfair","orders","quantity"],"backgroundTag":"internal-invariant-violation","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"}