nautechsystems/nautilus_trader · error · anyhow::Error
Pool {} does not have exactly one deployment manifest defini
Error message
Pool {} does not have exactly one deployment manifest definition What it means
`validate_manifest_pool` (crates/adapters/blockchain/src/execution/client.rs:4125) looks up the plan's pool address in the deployment manifest and requires exactly one matching pool entry, since it must resolve unique token0/token1/factory/quote-contract identities for the pool. Zero matches means the pool is not in the manifest; more than one means duplicate or conflicting definitions.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:4125
);
Ok((
quote.amount,
derive_min_amount_out(base_amount, slippage_bps)?,
))
}
}
}
fn validate_manifest_pool(
plan: &SwapPlan,
manifest: &BlockchainDeploymentManifest,
) -> anyhow::Result<Address> {
let matching = manifest
.pools
.iter()
.filter(|pool| Address::from_str(&pool.address).ok() == Some(plan.pool_address))
.collect::<Vec<_>>();
anyhow::ensure!(
matching.len() == 1,
"Pool {} does not have exactly one deployment manifest definition",
plan.pool_address
);
let pool = matching[0];
let token0 = Address::from_str(&pool.token0)?;
let token1 = Address::from_str(&pool.token1)?;
let factory = Address::from_str(&pool.factory)?;
let quote_contract = Address::from_str(&pool.quote_contract)?;
anyhow::ensure!(
token0 == plan.pool.token0.address
&& token1 == plan.pool.token1.address
&& pool.fee == plan.pool.fee.expect("validated pool fee")
&& factory == plan.factory,
"Cached pool {} does not match its deployment manifest identity",
plan.pool_address
);
View on GitHub (pinned to 18893faf8b)
Solutions
- Add a single definition for the pool (address, token0, token1, fee, factory, quote_contract) to the deployment manifest, or point the client at the manifest that contains it.
- Deduplicate the pools list in the manifest so each pool address appears exactly once.
- Confirm the pool address in the SwapPlan matches the manifest entry exactly (same address bytes).
- Regenerate/redeploy the manifest from source so it is in sync with the deployed pools.
Example fix
// before: duplicate pool entries in the manifest
"pools": [
{ "address": "0xabc...", "fee": 3000 },
{ "address": "0xabc...", "fee": 3000 }
]
// after: exactly one entry per pool address
"pools": [
{ "address": "0xabc...", "fee": 3000, "token0": "...", "token1": "...", "factory": "...", "quoteContract": "..." }
] Defensive patterns
Strategy: validation
Validate before calling
let matches: Vec<_> = manifest.pools.iter()
.filter(|p| Address::from_str(&p.address).ok() == Some(plan.pool_address))
.collect();
if matches.len() != 1 { return Err("pool must appear exactly once in the manifest"); } Type guard
fn has_unique_pool(manifest: &BlockchainDeploymentManifest, addr: Address) -> bool {
manifest.pools.iter()
.filter(|p| Address::from_str(&p.address).ok() == Some(addr))
.count() == 1
} Try / catch
match client.execute_swap(plan).await {
Err(e) if e.to_string().contains("exactly one deployment manifest definition") => {
// reload or repair the manifest, then retry
}
other => other?,
} Prevention
- Run a startup check that every pool in use appears exactly once in the manifest.
- Normalize pool addresses (lowercase) when generating the manifest to avoid duplicate variants.
- Version and checksum manifests so clients refuse stale or mixed-environment files.
- Deduplicate merged deployment files before shipping them.
When it happens
Trigger: Executing a swap whose plan.pool_address does not appear in the deployment manifest's pools list (0 matches), or the manifest contains the same pool address twice or across multiple environments/chains (>=2 matches).
Common situations: Stale or incomplete deployment manifest missing a newly created pool; pool address typo or checksum/case variant handled differently; manifest merged from multiple deployment files duplicating a pool entry; running against a different environment's manifest than the one the pool was deployed in.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- Chain ID mismatch at connect: expected {expected_chain_id},
- Unsupported blockchain {blockchain} for RPC connection
- Pool venue chain {blockchain} does not match the client chai
- Pool {instrument_id} tokens share a token priority; base and
- No durable store configured; refusing to submit a {} transac
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/5b36312a60de34b8.
Report an issue: GitHub.