nautechsystems/nautilus_trader · error · anyhow::Error
Allowed token pair {token_in} -> {token_out} is not fully pi
Error message
Allowed token pair {token_in} -> {token_out} is not fully pinned by the deployment manifest What it means
During manifest validation, every configured allowed token pair must have both tokens defined in the deployment manifest's token registry (token_decimals). If either address is missing from that registry, the pair cannot be trusted for swaps and validation fails. This ensures swap routing only uses tokens explicitly pinned by the deployment manifest.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:446
anyhow::ensure!(
token_decimals.contains_key(&weth),
"Deployment manifest has no wrapped native token identity"
);
if let Some(tokens) = &config.tokens {
for token in tokens {
let address = validate_address(token)?;
anyhow::ensure!(
token_decimals.contains_key(&address),
"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 {View on GitHub (pinned to 18893faf8b)
Solutions
- Add the missing token address (with correct decimals) to the deployment manifest's token registry
- Remove or correct the token pair in config.allowed_token_pairs
- Verify addresses are parsed consistently (same checksum format) via validate_address
Example fix
// before allowed_token_pairs = [["0xAAA...", "0xBBB..."]] // 0xBBB... not in manifest tokens // after # manifest.toml [[tokens]] address = "0xBBB..." decimals = 6
Defensive patterns
Strategy: validation
Validate before calling
// before calling preflight
for (tin, tout) in &config.allowed_token_pairs {
assert!(manifest.tokens.iter().any(|t| &t.address == tin), "token_in {} not in manifest", tin);
assert!(manifest.tokens.iter().any(|t| &t.address == tout), "token_out {} not in manifest", tout);
} Prevention
- Keep allowed_token_pairs and manifest token registry in sync via a single source of truth
- Add a CI check that validates config against the manifest
- Normalize address casing before comparing
When it happens
Trigger: Calling preflight/validate_manifest_contracts with config.allowed_token_pairs containing a token address that is not present in the manifest's token_decimals map, or a pair where token_in equals token_out.
Common situations: Operator adds a new trading pair to allowed_token_pairs but forgets to add the token (with decimals) to the deployment manifest; typo'd or checksummed-vs-lowercase address mismatch; manifest updated on another deployment.
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
- `router_addresses` must contain at least one router address
- Quote spend limit for {token_in} -> {token_out} is denominat
- Independent Blockchain execution verification is required
- Verification chain anchor ID does not match the configured c
- Verification chain anchor name does not match the configured
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/ca8ec006ead64870.
Report an issue: GitHub.