{"record":{"id":"e2ede37c9fcd5637","repo":"nautechsystems/nautilus_trader","slug":"failed-to-construct-maintenance-margin-e","errorCode":null,"errorMessage":"failed to construct maintenance margin: {e}","messagePattern":"failed to construct maintenance margin: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/lighter/src/websocket/parse.rs","lineNumber":1145,"sourceCode":"/// Returns an error if either `Money::from_decimal` call rejects the value.\npub fn margin_balance_from_user_stats(stats: &LighterUserStats) -> anyhow::Result<MarginBalance> {\n    margin_balance_from_user_stats_with_currency(stats, Currency::get_or_create_crypto(\"USDC\"))\n}\n\n/// Builds the cross-margin [`MarginBalance`] in the supplied settlement currency.\n///\n/// # Errors\n///\n/// Returns an error if either `Money::from_decimal` call rejects the value.\npub fn margin_balance_from_user_stats_with_currency(\n    stats: &LighterUserStats,\n    settlement_currency: Currency,\n) -> anyhow::Result<MarginBalance> {\n    let initial_dec = (stats.collateral - stats.available_balance).max(Decimal::ZERO);\n    let initial = Money::from_decimal(initial_dec, settlement_currency)\n        .map_err(|e| anyhow::anyhow!(\"failed to construct initial margin: {e}\"))?;\n    let maintenance = Money::from_decimal(Decimal::ZERO, settlement_currency)\n        .map_err(|e| anyhow::anyhow!(\"failed to construct maintenance margin: {e}\"))?;\n    Ok(MarginBalance::new(initial, maintenance, None))\n}\n\n/// Assembles the unified [`AccountState`] from already-parsed components.\n///\n/// The reconciler in the `websocket::account_state` module owns the latest\n/// snapshot of each input stream and calls this once per emission.\n/// `AccountType::Margin` is invariant for Lighter; `base_currency` is `None`\n/// because the account holds multiple spot currencies.\n#[must_use]\npub fn build_unified_account_state(\n    balances: Vec<AccountBalance>,\n    margin: Option<MarginBalance>,\n    account_id: AccountId,\n    ts_event: UnixNanos,\n    ts_init: UnixNanos,\n) -> AccountState {\n    let margins = margin.map(|m| vec![m]).unwrap_or_default();","sourceCodeStart":1127,"sourceCodeEnd":1163,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/lighter/src/websocket/parse.rs#L1127-L1163","documentation":"The same conversion function also constructs the maintenance margin as a fixed zero Money value via Money::from_decimal(Decimal::ZERO, settlement_currency). This should always succeed for any valid Currency, so this error only fires when the settlement currency itself is degenerate (e.g. zero/invalid precision) and from_decimal cannot represent even zero in it. It mirrors error 3401 as a defensive map_err on the maintenance-margin construction.","triggerScenarios":"Money::from_decimal(Decimal::ZERO, settlement_currency) fails, which in practice requires an invalid settlement Currency (e.g. precision 0 treated as invalid by Money construction rules) passed into margin_balance_from_user_stats_with_currency via build_state or margin_balance_from_user_stats.","commonSituations":"A Currency was constructed with precision 0 or otherwise malformed (e.g. loaded from bad config or a placeholder currency); a refactor passes the wrong type/units into the settlement currency argument.","solutions":["Inspect the settlement_currency passed in — confirm its precision is valid (>= 1) and it is the correct asset for the Lighter account.","Fix the Currency construction/source (currency catalog or config) rather than the parse code; zero itself is always representable in a valid currency.","Add an assertion/early check on currency.precision when building the AccountState so a bad currency fails fast with a clearer message.","If this error appears together with 3401, the root cause is the currency, not the arithmetic — prioritize fixing the Currency instance."],"exampleFix":"// before\nlet maintenance = Money::from_decimal(Decimal::ZERO, settlement_currency)\n    .map_err(|e| anyhow::anyhow!(\"failed to construct maintenance margin: {e}\"))?;\n\n// after\nassert!(settlement_currency.precision > 0, \"invalid settlement currency precision\");\nlet maintenance = Money::from_decimal(Decimal::ZERO, settlement_currency)\n    .map_err(|e| anyhow::anyhow!(\"failed to construct maintenance margin: {e}\"))?;","handlingStrategy":"validation","validationCode":"assert!(\n    settlement_currency.precision > 0,\n    \"settlement currency {} has invalid precision\",\n    settlement_currency.code\n);","typeGuard":null,"tryCatchPattern":"let maintenance = Money::from_decimal(Decimal::ZERO, settlement_currency)\n    .unwrap_or_else(|e| panic!(\"invalid settlement currency {:?}: {e}\", settlement_currency));","preventionTips":["Never construct Currency objects with precision 0 for crypto/fiat settlement assets.","Load currencies from the project's currency catalog instead of ad-hoc construction.","Validate currency configuration once at startup, not per-message."],"tags":["rust","account-state","margin","currency"],"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-14T00:17:10.932Z"}