nautechsystems/nautilus_trader · error · anyhow::Error

Quote spend limit decimals do not match the deployment manif

Error message

Quote spend limit decimals do not match the deployment manifest

What it means

Each configured quote spend limit declares the decimals of its spend_token; validation requires these to exactly match the decimals recorded for that token in the deployment manifest. A mismatch means the limit amount would be interpreted at the wrong precision, so validation fails.

Source

Thrown at crates/adapters/blockchain/src/execution/client.rs:456

                    "Configured token {address} has no deployment manifest identity"
                );
            }
        }

        for (token_in, token_out) in config.allowed_token_pairs.as_deref().unwrap_or_default() {
            let token_in = validate_address(token_in)?;
            let token_out = validate_address(token_out)?;
            anyhow::ensure!(
                token_in != token_out
                    && token_decimals.contains_key(&token_in)
                    && token_decimals.contains_key(&token_out),
                "Allowed token pair {token_in} -> {token_out} is not fully pinned by the deployment manifest"
            );
        }

        for limit in config.quote_spend_limits.as_deref().unwrap_or_default() {
            let spend_token = validate_address(&limit.spend_token)?;
            anyhow::ensure!(
                token_decimals.get(&spend_token) == Some(&limit.spend_token_decimals),
                "Quote spend limit decimals do not match the deployment manifest"
            );
        }

        let pool_contracts = role_addresses(BlockchainContractRole::Pool)?;

        for pool in &manifest.pools {
            let pool_address = Address::from_str(&pool.address)
                .map_err(|_| anyhow::anyhow!("Deployment manifest pool address is invalid"))?;
            let pool_factory = Address::from_str(&pool.factory)
                .map_err(|_| anyhow::anyhow!("Deployment manifest pool factory is invalid"))?;
            let pool_quote = Address::from_str(&pool.quote_contract).map_err(|_| {
                anyhow::anyhow!("Deployment manifest pool quote contract is invalid")
            })?;
            anyhow::ensure!(
                pool_contracts.contains(&pool_address)
                    && pool_factory == factory

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Update spend_token_decimals in config.quote_spend_limits to match the manifest value
  2. Update the token's decimals in the deployment manifest if the manifest value is stale/wrong
  3. Ensure spend_token is present in the manifest token registry at all

Example fix

// before
{ spend_token: "0xAAA...", spend_token_decimals: 18 } // manifest says 6
// after
{ spend_token: "0xAAA...", spend_token_decimals: 6 }
Defensive patterns

Strategy: validation

Validate before calling

for limit in config.quote_spend_limits {
    let m = manifest.tokens.iter().find(|t| t.address == limit.spend_token)
        .ok_or("spend token missing from manifest")?;
    assert_eq!(m.decimals, limit.spend_token_decimals, "decimals mismatch for {}", limit.spend_token);
}

Prevention

When it happens

Trigger: Calling preflight/validate_manifest_contracts when a config.quote_spend_limits entry has spend_token_decimals differing from token_decimals[spend_token] in the manifest, or the spend_token is absent from the manifest entirely.

Common situations: Token redefined with different decimals (e.g. USDC 6 vs 18 on a test chain); hand-edited config after a manifest update; copy-pasted limit config from another chain.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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