{"record":{"id":"8503ef9cf436f03c","repo":"nautechsystems/nautilus_trader","slug":"invalid-contract-size-contract-size","errorCode":null,"errorMessage":"Invalid contract size {contract_size}","messagePattern":"Invalid contract size (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/bitmex/src/common/parse.rs","lineNumber":163,"sourceCode":"/// The returned decimal retains BitMEX precision (clamped to `max_scale`) so downstream\n/// quantity conversions stay lossless.\n///\n/// # Errors\n///\n/// Returns an error when the multiplier cannot be represented with the configured precision.\npub fn derive_contract_decimal_and_increment(\n    multiplier: Option<f64>,\n    max_scale: u32,\n) -> anyhow::Result<(Decimal, Quantity)> {\n    let raw_multiplier = multiplier.unwrap_or(1.0);\n    let contract_size = if raw_multiplier > 0.0 {\n        1.0 / raw_multiplier\n    } else {\n        1.0\n    };\n\n    let mut contract_decimal = Decimal::from_str(&contract_size.to_string())\n        .map_err(|_| anyhow::anyhow!(\"Invalid contract size {contract_size}\"))?;\n\n    if contract_decimal.scale() > max_scale {\n        contract_decimal = contract_decimal\n            .round_dp_with_strategy(max_scale, RoundingStrategy::MidpointAwayFromZero);\n    }\n    contract_decimal = contract_decimal.normalize();\n    let contract_precision = contract_decimal.scale() as u8;\n    let size_increment = Quantity::from_decimal_dp(contract_decimal, contract_precision)?;\n\n    Ok((contract_decimal, size_increment))\n}\n\n/// Converts an optional contract-count field (e.g. `lotSize`, `maxOrderQty`) into a Nautilus\n/// quantity using the previously derived contract size.\n///\n/// # Errors\n///\n/// Returns an error when the raw value cannot be represented with the available precision.","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/bitmex/src/common/parse.rs#L145-L181","documentation":"derive_contract_decimal_and_increment parses the instrument's contract size (computed from the raw multiplier or defaulting to 1.0) into a Decimal and fails if the conversion is not representable. This guards instrument parsing so contract sizes stay exact Decimal values before scale normalization/rounding to max_scale.","triggerScenarios":"Parsing a spot/perpetual/futures/crypto-futures-spread instrument whose derived contract_size.to_string() cannot be parsed by Decimal::from_str (e.g. NaN, infinity, or a non-finite float produced by 1.0/raw_multiplier when raw_multiplier is 0).","commonSituations":"A BitMEX instrument row with an unexpected or zero initQuantity/lotSize multiplier yielding inf or NaN contract size; malformed instrument metadata from the exchange or test fixtures.","solutions":["Inspect the instrument payload's multiplier fields that feed raw_multiplier; correct or filter the malformed instrument","Guard the caller against raw_multiplier == 0 before deriving the contract decimal","Confirm the BitMEX instrument definition is current; reload the instrument list after an exchange listing update"],"exampleFix":"// before\nlet raw_multiplier = 1.0 / init_quantity; // NaN/inf if init_quantity == 0\n// after\nif init_quantity == 0.0 {\n    return Err(anyhow::anyhow!(\"Instrument {symbol} has zero initQuantity\"));\n}","handlingStrategy":"validation","validationCode":"fn contract_size_parsable(raw_multiplier: f64) -> bool {\n    raw_multiplier.is_finite() && raw_multiplier != 0.0 && !(1.0 / raw_multiplier).is_finite()\n}","typeGuard":"fn finite_f64(x: f64) -> bool { x.is_finite() }","tryCatchPattern":"match parse_instrument(&row) {\n    Ok(inst) => inst,\n    Err(e) if e.to_string().contains(\"Invalid contract size\") => {\n        log::warn!(\"skipping instrument with bad contract size: {e}\");\n        return None;\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Sanity-check multiplier fields (initQuantity/lotSize) for zero or non-finite values before parsing instruments","Keep instrument definitions refreshed from the exchange","Reject malformed instrument rows early in data ingestion"],"tags":["instrument-parsing","decimal","contract-size"],"backgroundTag":"invalid-argument-value","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}