nautechsystems/nautilus_trader · error · anyhow::Error
Pool identifier must be 42 chars (address) or 66 chars (pool
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.
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)
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: {s}
- Invalid tick range: {tick_lower} >= {tick_upper}
- {e}
- Native currency not specified for chain {}
- Must have the `chain` field set
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/5995a6441e051124.
Report an issue: GitHub.