nautechsystems/nautilus_trader · error · anyhow::Error
Pool identifier must be 42 chars (address) or 66 chars…
Error message
Pool identifier must be 42 chars (address) or 66 chars (pool ID), was {len} chars: {value} What it means
PoolIdentifier::new_checked only accepts identifiers of exactly 42 characters (an EVM address) or 66 characters (a 32-byte V4 pool ID), both with 0x prefix and valid hex. Any other length is rejected. This enforces the two canonical pool identifier shapes the model layer supports.
Solutions
- Count the characters of the value and ensure it is exactly 42 or 66 including the '0x' prefix
- Add the '0x' prefix if missing (an unprefixed 40-char address or 64-char pool ID fails)
- Verify you are passing an on-chain identifier, not a human-readable pool name or symbol
- Use PoolIdentifier::new_address or from_pool_id_hex helpers which make the intended variant explicit
Example fix
// before
let pid = PoolIdentifier::new_checked("a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48")?;
// after
let pid = PoolIdentifier::new_checked("0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48")?; // 42 chars Defensive patterns
Strategy: validation
Validate before calling
fn is_valid_pool_identifier(s: &str) -> bool {
let len = s.len();
(len == 42 || len == 66) && s.starts_with("0x") && s[2..].chars().all(|c| c.is_ascii_hexdigit())
} Prevention
- Always store pool identifiers with the 0x prefix
- Assert length 42 or 66 at config-load time
- Never pass human-readable pool names to PoolIdentifier
When it happens
Trigger: Calling PoolIdentifier::new_checked with a string whose length is not 42 or 66 — e.g. a truncated hex string, an address missing '0x' (40 chars), a pool ID without '0x' (64 chars), or arbitrary pool names/symbols.
Common situations: Config files or venue parameters holding a shortened or unprefixed address; passing a Uniswap V3 fee-tier name or pool label instead of an on-chain identifier; slicing errors when copying pool IDs from explorers.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Invalid hex characters in
- Invalid tick range: >=
- AX dated contract has different quote and settlement…
- AX scale must not exceed 26 for exact percent conversion…
- AX fills applied limit must be between 0 and
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/5995a6441e051124.
Report an issue: GitHub.
Appendix: source
Thrown at crates/model/src/defi/pool_identifier.rs:92
validate_hex_string(value)?;
// Parse without strict checksum validation, then normalize to checksummed format
let addr = value
.parse::<Address>()
.map_err(|e| anyhow::anyhow!("Invalid address: {e}"))?;
// Store the checksummed version
Ok(Self::Address(Ustr::from(addr.to_checksum(None).as_str())))
}
66 => {
// PoolId variant (32 bytes)
validate_hex_string(value)?;
// Store lowercase version for consistency
Ok(Self::PoolId(Ustr::from(&value.to_lowercase())))
}
len => {
anyhow::bail!(
"Pool identifier must be 42 chars (address) or 66 chars (pool ID), was {len} chars: {value}"
)
}
}
}
/// Creates a new [`PoolIdentifier`] instance.
///
/// # Panics
///
/// Panics if validation fails.
#[must_use]
pub fn new<T: AsRef<str>>(value: T) -> Self {
Self::new_checked(value).expect(FAILED)
}
/// Creates an Address variant from an alloy Address.
///View on GitHub (pinned to 18893faf8b)