nautechsystems/nautilus_trader · error
Pool {instrument_id} references factory {}, expected registe
Error message
Pool {instrument_id} references factory {}, expected registered factory {factory} What it means
Before executing a swap the client verifies that the pool's DEX factory matches the Uniswap V3 factory registered with the client. If the pool was deployed by a different factory, the swap plan is rejected to avoid interacting with an untrusted pool.
Source
Thrown at crates/adapters/blockchain/src/execution/client.rs:1723
anyhow::bail!(
"BUY quote amount {amount_in} exceeds the configured `quote_spend_limits` maximum {} for {token_in} -> {token_out}",
ceiling.max_amount
);
}
(amount_in, base_amount)
}
};
let min_amount_out = derive_min_amount_out(quoted_amount_out, slippage_bps)?;
self.ensure_transaction_ready(TransactionPurpose::Swap)?;
if self.signer.is_none() {
anyhow::bail!("Signer not initialized; connect the client first");
}
let pool_address = pool.address;
let factory = self.uniswap_v3_factory()?;
anyhow::ensure!(
pool.dex.factory == factory,
"Pool {instrument_id} references factory {}, expected registered factory {factory}",
pool.dex.factory
);
Ok(SwapPlan {
order: order.clone(),
pool,
quote_currency,
instrument_id,
pool_address,
router: self.router_addresses[0],
factory,
weth: self.weth_address,
token_in,
token_out,
fee,
amount_in,View on GitHub (pinned to 18893faf8b)
Solutions
- Register the factory that actually deployed the pool, or use a pool from the registered factory's deployment.
- Verify the factory address and chain configuration match the pool's network.
- Check that pool.dex.factory was populated from the correct on-chain `factory()` call.
- Confirm the client is connected to the same chain the pool lives on.
Example fix
// before: pool from a fork factory // uniswap_v3_factory = 0x1F98431c8aD... (Uniswap) pool.dex.factory = 0x0BFbCF9fa4f9C56B0F40a671Ad40E0805A091865; // PancakeSwap // after: use the matching pool/factory let factory = self.uniswap_v3_factory()?; let pool = registry.get_pool_by_factory(factory, ...)?;
Defensive patterns
Strategy: validation
Validate before calling
let factory = client.registered_factory()?;
if pool.dex.factory != factory { return Err("pool factory mismatch"); } Type guard
fn pool_matches_factory(pool: &Pool, factory: Address) -> bool { pool.dex.factory == factory } Try / catch
match client.submit_order(order) { Err(e) if e.to_string().contains("expected registered factory") => switch_to_compliant_pool(e), Ok(r) => r } Prevention
- Register only factories whose pools you trade
- Verify pool.factory() on-chain when loading pools
- Pin chain and factory config together
When it happens
Trigger: Calling submit_order -> prepare_swap for a pool whose `pool.dex.factory` differs from the address returned by `self.uniswap_v3_factory()` — e.g. pool created on a fork or different deployment than the configured factory.
Common situations: Configured factory address points at Uniswap V3 while the pool is from PancakeSwap/Sushi or a fork; wrong chain configured so addresses resolve to different deployments; typo in factory registration.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- Invalid tick range: {tick_lower} >= {tick_upper}
- Deployment manifest pool fee is invalid
- Invalid factory address for DEX {name} on chain {chain} for
- request_rate_per_second must be greater than zero
- order_request_rate_per_second must be greater than zero
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/be84e3d75b5e73d1.
Report an issue: GitHub.