nautechsystems/nautilus_trader · error

Cannot update {currency} reservation: precision {} differed

Error message

Cannot update {currency} reservation: precision {} differed from balance precision {}

What it means

A balance reservation for a currency must have the same decimal precision as the account's existing balance in that currency; a differing precision would corrupt the balance arithmetic. The guard rejects the reservation update when `locked.currency.precision` differs from the current balance currency's precision.

Source

Thrown at crates/model/src/accounts/base.rs:442

/// or the reservations cannot produce a valid balance. Balances and reservations are left
/// unchanged when an error is returned.
pub(crate) fn update_balance_locked(
    balances: &mut IndexMap<Currency, AccountBalance>,
    balances_locked: &mut AHashMap<(InstrumentId, Currency), Money>,
    instrument_id: InstrumentId,
    locked: Money,
) -> anyhow::Result<()> {
    anyhow::ensure!(locked.raw >= 0, "locked balance was negative: {locked}");

    let currency = locked.currency;
    let key = (instrument_id, currency);

    let Some(current_balance) = balances.get(&currency).copied() else {
        balances_locked.insert(key, locked);
        return Ok(());
    };

    anyhow::ensure!(
        current_balance.currency.precision == currency.precision,
        "Cannot update {currency} reservation: precision {} differed from balance precision {}",
        currency.precision,
        current_balance.currency.precision
    );

    let previous = balances_locked.insert(key, locked);

    match balance_from_locks(current_balance, balances_locked) {
        Ok(balance) => {
            balances.insert(currency, balance);
            Ok(())
        }
        Err(e) => {
            // Restore the prior reservation so a rejected update leaves nothing behind
            match previous {
                Some(previous) => balances_locked.insert(key, previous),
                None => balances_locked.remove(&key),

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Construct the locked Money using the same Currency instance/precision as the account balance (use Currency.from_str or the canonical currency)
  2. Normalize adapter-reported precision to the account's precision before reserving
  3. Check the account's balance snapshot to confirm the precision the account expects
Defensive patterns

Strategy: validation

Validate before calling

if locked.currency.precision != balances[locked.currency].currency.precision:
    locked = Money(locked.as_decimal(), balances[locked.currency].currency)

Try / catch

try:
    update_balance_locked(balances, locks, instrument_id, locked)
except Exception as e:
    log.warning(f"reservation rejected: {e}")

Prevention

When it happens

Trigger: Calling update_balance_locked with a Money whose currency carries a different precision than the precision of the account's existing balance for that currency (e.g. BTC with 8 vs 6 digits, or USD 2 vs 0).

Common situations: Adapters reporting balances/reservations with different decimal precision than the configured account currency, currency objects constructed ad hoc with the wrong precision, or mixing custom Currency instances with the canonical ones.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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