nautechsystems/nautilus_trader · error
Input token {} balance {} is below the swap amount {}
Error message
Input token {} balance {} is below the swap amount {} What it means
Before submitting a swap, the client checks the wallet's balance of the input token. This error is thrown when the balance is strictly less than the swap's amount_in, meaning the swap cannot be funded and would revert on-chain.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:5183
}
.abi_encode();
let balance = required_verification(
executor
.verification
.verify_decoded_call(
None,
&plan.token_in,
U256::ZERO,
&balance_call,
block,
|result| ERC20::balanceOfCall::abi_decode_returns(result).map_err(Into::into),
)
.await,
"swap input balance",
)?;
if balance.value < plan.amount_in {
anyhow::bail!(
"Input token {} balance {} is below the swap amount {}",
plan.token_in,
balance.value,
plan.amount_in
);
}
decisions.push(verification_decision(&balance, Some(block), Some(block)));
Ok(decisions)
}
/// Converts a base-denominated order quantity into raw token units with exact integer
/// scaling by the base token decimals.
///
/// `Quantity::raw` is scaled to the greater of its declared precision and `FIXED_PRECISION`;
/// token amounts are scaled to the token's decimals. Quantities not exactly representable in
/// token units are rejected rather than rounded.
fn quantity_to_raw_amount(quantity: Quantity, decimals: u8) -> anyhow::Result<U256> {View on GitHub (pinned to 18893faf8b)
Solutions
- Re-fetch the on-chain balance and resize the swap to amount_in <= balance
- Verify token decimals are correct so amount_in is scaled properly
- Transfer or acquire the shortfall of token_in before retrying
- Check for other pending transactions consuming the same balance (nonce queue)
Example fix
// before: sizing from stale cached balance let plan = SwapPlan::new(token_in, cached_balance); // after: refresh balance and clamp the amount let balance = token.balance_of(wallet).await?; let plan = SwapPlan::new(token_in, plan.amount_in.min(balance));
Defensive patterns
Strategy: validation
Validate before calling
let balance = token.balance_of(wallet).await?;
anyhow::ensure!(balance >= plan.amount_in, "insufficient token_in balance: {} < {}", balance, plan.amount_in); Try / catch
match res {
Err(e) if e.to_string().contains("balance") => {
let balance = token.balance_of(wallet).await?;
submit_swap(plan.resized_to(balance)).await?;
}
other => other?,
} Prevention
- Refresh on-chain balances immediately before sizing orders
- Validate token decimals against the contract, not config alone
- Account for pending outgoing transfers in available balance
- Clamp swap sizes to current balance rather than cached values
When it happens
Trigger: Submitting a swap plan where token_in's balance (queried via the token contract) is below plan.amount_in — e.g. plan sized from stale balance data, tokens transferred out, or amount including fees the wallet cannot cover.
Common situations: Stale balance cache after recent transfers or another trade; token decimals mismatch causing an inflated amount_in; funds locked in another position or pending withdrawal; swap sized from a quote denominated in a different unit.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- Input token {} balance {balance} is below the swap amount {}
- Router allowance {} is below the swap amount {} for input to
- No deployed bytecode at {description} address {address}
- Router allowance {allowance} is below the swap amount {} for
- HyperSync parsing of swap event is not defined in this dex:
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/54d5b07d9d72fca0.
Report an issue: GitHub.