{"record":{"id":"26b74958d5f2c185","repo":"nautechsystems/nautilus_trader","slug":"ax-field-scale-must-not-exceed-26-for-exact-perc","errorCode":null,"errorMessage":"AX {field} scale must not exceed 26 for exact percent conversion, was {scale}","messagePattern":"AX (.+?) scale must not exceed 26 for exact percent conversion, was (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/architect_ax/src/http/parse.rs","lineNumber":399,"sourceCode":"    anyhow::ensure!(\n        maintenance_margin_pct > Decimal::ZERO,\n        \"AX maintenance_margin_pct must be positive, was {maintenance_margin_pct}\"\n    );\n    anyhow::ensure!(\n        maintenance_margin_pct <= initial_margin_pct,\n        \"AX maintenance_margin_pct {maintenance_margin_pct} exceeds initial_margin_pct {initial_margin_pct}\"\n    );\n\n    Ok((\n        margin_percent_to_rate(initial_margin_pct, \"initial_margin_pct\")?,\n        margin_percent_to_rate(maintenance_margin_pct, \"maintenance_margin_pct\")?,\n    ))\n}\n\nfn margin_percent_to_rate(value: Decimal, field: &str) -> anyhow::Result<Decimal> {\n    let normalized = value.normalize();\n    let scale = normalized.scale();\n    anyhow::ensure!(\n        scale <= 26,\n        \"AX {field} scale must not exceed 26 for exact percent conversion, was {scale}\"\n    );\n    Decimal::try_from_i128_with_scale(normalized.mantissa(), scale + 2)\n        .with_context(|| format!(\"Failed to convert AX {field} percentage to a rate\"))\n}\n\n/// Parses an Ax balances response into a Nautilus [`AccountState`].\n///\n/// Ax provides a simple balance structure with symbol and amount.\n/// The amount is treated as both total and free balance (no locked funds tracking).\n///\n/// # Errors\n///\n/// Returns an error if balance amount parsing fails.\npub fn parse_account_state(\n    response: &AxBalancesResponse,\n    account_id: AccountId,","sourceCodeStart":381,"sourceCodeEnd":417,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/architect_ax/src/http/parse.rs#L381-L417","documentation":"margin_percent_to_rate converts a percentage (e.g. 10 meaning 10%) to a rate (0.10) by scaling the Decimal mantissa by 2. rust_decimal supports at most 28-29 significant digits with scale <= 28; adding 2 to the scale requires the normalized scale to be <= 26 to keep the conversion exact. Larger scales would overflow or lose precision, so the adapter fails fast.","triggerScenarios":"parse_margin_rates (invoked by parse_instrument) on margin percentages whose normalized Decimal representation has more than 26 fractional digits — e.g. a value like 0.1234567890123456789012345678 normalized to a scale above 26.","commonSituations":"Venue sending absurdly precise margin values, a feed bug producing repeated decimal expansions, or fixtures generated with full-precision floats serialized to Decimal.","solutions":["Round the margin percentage at the data source to a sane precision (e.g. 8 decimal places) before parsing.","Check whether the venue value is meant to be a fraction already (0.0001) rather than a high-precision percent.","Fix float-to-Decimal fixture generation to quantize values.","Only if genuinely needed, raise precision handling in the adapter with maintainer guidance."],"exampleFix":"// before\nlet init = Decimal::from_str(\"0.100000000000000000000000000001\")?;\n// after\nlet init = Decimal::from_str(\"0.10\")?;","handlingStrategy":"validation","validationCode":"fn margin_scale_ok(v: Decimal) -> bool { v.normalize().scale() <= 26 }","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Quantize margin percentages (e.g. scale 8) at ingestion","Avoid converting raw f64 with full binary precision into Decimal","Round venue-provided percentages to a sane precision before parsing"],"tags":["rust","decimal","precision","validation"],"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"}