nautechsystems/nautilus_trader · error · anyhow::Error
Invalid hex characters in: {s}
Error message
Invalid hex characters in: {s} What it means
validate_hex_string checks that all characters after the mandatory '0x' prefix are ASCII hex digits. Any non-hex character after '0x' is rejected with this error. It backs new_checked and from_pool_id_hex.
Source
Thrown at crates/model/src/defi/pool_identifier.rs:221
///
/// Returns error if this is an Address variant or if hex decoding fails.
pub fn to_pool_id_bytes(&self) -> anyhow::Result<[u8; 32]> {
match self {
Self::PoolId(s) => {
let hex_str = s.strip_prefix("0x").unwrap_or(s.as_str());
hex::decode_array::<32>(hex_str)
.map_err(|e| anyhow::anyhow!("Failed to decode pool ID hex: {e}"))
}
Self::Address(_) => anyhow::bail!("Cannot convert Address variant to PoolId bytes"),
}
}
}
/// Validates that a string contains only valid hexadecimal characters after "0x" prefix.
fn validate_hex_string(s: &str) -> anyhow::Result<()> {
let hex_part = &s[2..];
if !hex_part.chars().all(|c| c.is_ascii_hexdigit()) {
anyhow::bail!("Invalid hex characters in: {s}");
}
Ok(())
}
impl PartialEq for PoolIdentifier {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Self::Address(a), Self::Address(b)) | (Self::PoolId(a), Self::PoolId(b)) => {
// Case-insensitive comparison
a.eq_ignore_ascii_case(b)
}
// Different variants are never equal
_ => false,
}
}
}
impl Eq for PoolIdentifier {}View on GitHub (pinned to 18893faf8b)
Solutions
- Inspect the string for non [0-9a-fA-F] characters after '0x'
- Strip whitespace and trailing punctuation before constructing
- Validate with a regex/scan before calling new_checked or from_pool_id_hex
Example fix
// before
let pid = PoolIdentifier::new_checked("0x 9243eb4d")?;
// after
let cleaned = value.trim();
assert!(cleaned[2..].chars().all(|c| c.is_ascii_hexdigit()));
let pid = PoolIdentifier::new_checked(cleaned)?; Defensive patterns
Strategy: validation
Validate before calling
fn is_valid_hex_id(s: &str) -> bool {
s.len() >= 2 && s.starts_with("0x") && s[2..].chars().all(|c| c.is_ascii_hexdigit())
} Prevention
- Trim whitespace before constructing identifiers
- Sanitize copy-pasted values (no spaces, labels, or annotations)
- Validate with a regex ^0x[0-9a-fA-F]+$ before calling
When it happens
Trigger: Passing a pool identifier or pool ID containing non-hex characters after '0x' — e.g. whitespace, placeholders like '0x<pool_id>', or labels appended to the ID.
Common situations: Copy-paste errors from docs or explorers including spaces or annotations; template placeholders not substituted; encoding bugs producing non-ASCII lookalike characters.
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
- Pool identifier must be 42 chars (address) or 66 chars (pool
- 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/e0910bdc46978add.
Report an issue: GitHub.