{"record":{"id":"fef3d59c39ad4e5e","repo":"nautechsystems/nautilus_trader","slug":"quote-spend-limit-for-token-in-token-out-is-fef3d5","errorCode":null,"errorMessage":"Quote spend limit for {token_in} -> {token_out} is denominated in {}, expected quote token {}","messagePattern":"Quote spend limit for (.+?) -> (.+?) is denominated in (.+?), expected quote token (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":1635,"sourceCode":"\n        if slippage_bps > self.transaction_limits.max_slippage_bps {\n            anyhow::bail!(\n                \"Slippage {slippage_bps} bps exceeds the configured `max_slippage_bps` {}\",\n                self.transaction_limits.max_slippage_bps\n            );\n        }\n\n        let quote_spend_ceiling = if order.order_side() == OrderSide::Buy {\n            let ceiling = self\n                .transaction_limits\n                .quote_spend_limits\n                .get(&(token_in, token_out))\n                .ok_or_else(|| {\n                    anyhow::anyhow!(\n                        \"No `quote_spend_limits` entry for BUY token pair {token_in} -> {token_out}\"\n                    )\n                })?;\n            anyhow::ensure!(\n                ceiling.spend_token == quote_token.address,\n                \"Quote spend limit for {token_in} -> {token_out} is denominated in {}, expected quote token {}\",\n                ceiling.spend_token,\n                quote_token.address\n            );\n            anyhow::ensure!(\n                ceiling.spend_token_decimals == quote_token.decimals,\n                \"Quote spend limit for token {} uses {} decimals, expected pool quote-token decimals {}\",\n                ceiling.spend_token,\n                ceiling.spend_token_decimals,\n                quote_token.decimals\n            );\n            Some(ceiling)\n        } else {\n            None\n        };\n\n        let profiler = self","sourceCodeStart":1617,"sourceCodeEnd":1653,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/client.rs#L1617-L1653","documentation":"For BUY swaps the configured quote-spend ceiling must be denominated in the pool's actual quote token. If `ceiling.spend_token` differs from `quote_token.address`, the cap would limit the wrong asset, so the swap is rejected.","triggerScenarios":"`prepare_swap()` on a BUY order where the `quote_spend_limits` entry's `spend_token` address does not equal the pool's quote-token address.","commonSituations":"Pool where the configured 'quote' differs from the actual pool quote token (e.g. USDT vs USDC pair swapped); copy-pasted limit entry between markets; token address checksum/case mismatch.","solutions":["Correct the ceiling's `spend_token` to the pool's actual quote-token address","Fix the (token_in, token_out) key so the ceiling matches the pair actually being swapped","Recompute the spend limit if the real quote token has different decimals/value"],"exampleFix":"// before\nspend_token: USDT_ADDRESS // pool quote is USDC\n// after\nspend_token: USDC_ADDRESS // matches quote_token.address","handlingStrategy":"validation","validationCode":"let ceiling = limits.get(&(token_in, token_out)).ok_or(\"missing ceiling\")?;\nif ceiling.spend_token != quote_token.address {\n    return Err(\"ceiling denominated in wrong token\".into());\n}","typeGuard":"fn ceiling_matches_quote(ceiling: &Ceiling, quote: &Token) -> bool {\n    ceiling.spend_token == quote.address\n}","tryCatchPattern":"match client.submit_order(buy_order).await {\n    Err(e) if e.to_string().contains(\"denominated in\") => {\n        reload_spend_limits_for_pair(token_in, token_out)?;\n        client.submit_order(buy_order).await\n    }\n    r => r,\n}","preventionTips":["Generate spend-limit entries from pool metadata so spend_token always matches the real quote token","Verify pool token ordering (token0/token1 vs base/quote) when configuring limits","Don't copy ceiling entries between markets with different quote tokens"],"tags":["configuration","risk-limits","token-mismatch","swap"],"backgroundTag":"invalid-config-value","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}