nautechsystems/nautilus_trader · error · anyhow::Error
No quote spend ceiling for BUY token pair {} -> {}
Error message
No quote spend ceiling for BUY token pair {} -> {} What it means
In `verified_swap_amounts` (crates/adapters/blockchain/src/execution/client.rs:4094), BUY orders route tokens with the swap's input amount coming from the quote, so a hard ceiling on how much quote token may be spent is mandatory. This error means the SwapPlan for a BUY order has `quote_spend_ceiling == None`, so the client cannot bound the spend and aborts instead of executing an unbounded trade.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:4094
}
}
fn verified_swap_amounts(plan: &SwapPlan, quote: UniswapV3Quote) -> anyhow::Result<(U256, U256)> {
anyhow::ensure!(
!quote.amount.is_zero(),
"Independent swap quote returned zero"
);
let base_amount =
quantity_to_raw_amount(plan.order.quantity(), plan.pool.get_base_token().decimals)?;
let slippage_bps = plan.slippage_bps;
match plan.order.order_side() {
OrderSide::Sell => Ok((
base_amount,
derive_min_amount_out(quote.amount, slippage_bps)?,
)),
OrderSide::Buy => {
let ceiling = plan.quote_spend_ceiling.ok_or_else(|| {
anyhow::anyhow!(
"No quote spend ceiling for BUY token pair {} -> {}",
plan.token_in,
plan.token_out
)
})?;
anyhow::ensure!(
quote.amount <= ceiling.max_amount,
"BUY quote amount {} exceeds the configured quote-spend maximum {} for {} -> {}",
quote.amount,
ceiling.max_amount,
plan.token_in,
plan.token_out
);
Ok((
quote.amount,
derive_min_amount_out(base_amount, slippage_bps)?,
))
}View on GitHub (pinned to 18893faf8b)
Solutions
- Set quote_spend_ceiling (with max_amount in quote-token raw units) on the SwapPlan for every BUY order.
- If building plans from config, ensure the quote-spend maximum is loaded and validated for buy-side orders before plan creation.
- Only use OrderSide::Buy when the caller can supply a spend ceiling; otherwise convert the intent to a Sell-side formulation.
- Reject BUY plans without a ceiling at plan construction with a clear error instead of at quote time.
Example fix
// before
let plan = SwapPlan {
order,
token_in,
token_out,
quote_spend_ceiling: None,
..plan_base
};
// after
let plan = SwapPlan {
order,
token_in,
token_out,
quote_spend_ceiling: Some(QuoteSpendCeiling { max_amount: max_quote_spend_raw }),
..plan_base
}; Defensive patterns
Strategy: validation
Validate before calling
if plan.order.order_side() == OrderSide::Buy && plan.quote_spend_ceiling.is_none() {
return Err("BUY plan requires quote_spend_ceiling");
} Type guard
fn has_buy_ceiling(plan: &SwapPlan) -> bool {
plan.order.order_side() != OrderSide::Buy || plan.quote_spend_ceiling.is_some()
} Try / catch
match client.execute_swap(plan).await {
Err(e) if e.to_string().contains("No quote spend ceiling") => {
// rebuild the plan with a ceiling and retry once
}
other => other?,
} Prevention
- Validate at SwapPlan construction that every BUY plan carries a spend ceiling.
- Load the quote-spend maximum from config and fail fast at startup if absent.
- Add a builder method that makes the ceiling mandatory for buy-side plans.
- Cover both order sides in unit tests for plan construction.
When it happens
Trigger: Constructing a SwapPlan with order_side()==Buy but leaving quote_spend_ceiling unset, then running it through quote verification / verified_swap_amounts.
Common situations: An adapter or strategy builder that sets the ceiling only for SELL plans; a config loader that omits the max-spend field; refactored code paths that construct SwapPlan manually without the ceiling; an upgrade where quote_spend_ceiling was newly introduced and old callers were not migrated.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- Token pair {token_in} -> {token_out} is not in the `allowed_
- Order amount {base_amount} exceeds the configured `max_order
- Slippage {slippage_bps} bps exceeds the configured `max_slip
- BUY quote amount {amount_in} exceeds the configured `quote_s
- BUY quote amount {} exceeds the configured quote-spend maxim
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/cd94e470064f896c.
Report an issue: GitHub.