nautechsystems/nautilus_trader · error

Cash account balance would become negative

Error message

Cash account balance would become negative: {} {} (borrowing not allowed for {})

What it means

CashAccount::update_balances rejects negative balance totals when the account was created with allow_borrowing=false, since a cash account without borrowing cannot go below zero. The error reports the total, currency, and account id.

Solutions

  1. Enable borrowing at account construction if negative balances are expected
  2. Correct the balance data so totals stay non-negative
  3. Route flows requiring negative balances to a margin account instead

Example fix

// before
let mut acct = CashAccount::new(..., false); // allow_borrowing=false
acct.update_balances(&balances_with_negative_total)?; // bails
// after
let mut acct = CashAccount::new(..., true); // allow_borrowing=true
acct.update_balances(&balances_with_negative_total)?;
Defensive patterns

Strategy: validation

Validate before calling

if !acct.allows_borrowing() && balances.iter().any(|b| b.total.raw < 0) { /* reject or enable borrowing */ }
acct.update_balances(balances)?;

Type guard

fn balances_non_negative(bs: &[AccountBalance]) -> bool {
    bs.iter().all(|b| b.total.raw >= 0)
}

Try / catch

match acct.update_balances(balances) {
    Err(e) if e.to_string().contains("would become negative") => { /* enable borrowing or clamp */ }
    other => other?,
}

Prevention

When it happens

Trigger: Calling update_balances() on a CashAccount with allow_borrowing=false and any AccountBalance in the slice whose total.raw < 0.

Common situations: Backtest engines applying withdrawal/fee events that overdraw a non-borrowing cash account; configuring an account without borrowing then routing margin-like flows through it.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/eb3c74d5326201db. Report an issue: GitHub.

Appendix: source

Thrown at crates/model/src/accounts/cash.rs:136

        base::clear_balance_locked(
            &mut self.base.balances,
            &mut self.balances_locked,
            instrument_id,
        );
    }

    /// Updates the account balances, enforcing borrowing constraints.
    ///
    /// # Errors
    ///
    /// Returns an error if `allow_borrowing` is false and any balance has a negative total.
    ///
    /// TODO: Force stop backtest engine on error (like Python's `set_backtest_force_stop`)
    pub fn update_balances(&mut self, balances: &[AccountBalance]) -> anyhow::Result<()> {
        if !self.allow_borrowing {
            for balance in balances {
                if balance.total.raw < 0 {
                    anyhow::bail!(
                        "Cash account balance would become negative: {} {} (borrowing not allowed for {})",
                        balance.total.as_decimal(),
                        balance.currency.code,
                        self.id
                    );
                }
            }
        }
        self.base.update_balances(balances);
        Ok(())
    }

    #[must_use]
    pub fn is_cash_account(&self) -> bool {
        self.account_type == AccountType::Cash
    }

    #[must_use]

View on GitHub (pinned to 18893faf8b)