{"record":{"id":"2e9fee6a3f3da28d","repo":"nautechsystems/nautilus_trader","slug":"pool-id-hex-must-be-64-characters-32-bytes-was","errorCode":null,"errorMessage":"Pool ID hex must be 64 characters (32 bytes), was {}","messagePattern":"Pool ID hex must be 64 characters \\(32 bytes\\), was (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/model/src/defi/pool_identifier.rs","lineNumber":141,"sourceCode":"        anyhow::ensure!(\n            bytes.len() == 32,\n            \"Pool ID must be 32 bytes, was {}\",\n            bytes.len()\n        );\n\n        Ok(Self::PoolId(Ustr::from(&hex::encode_prefixed(bytes))))\n    }\n\n    /// Creates a `PoolId` variant from a hex string (with or without 0x prefix).\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the string is not valid 64-character hex.\n    pub fn from_pool_id_hex<T: AsRef<str>>(hex: T) -> anyhow::Result<Self> {\n        let hex = hex.as_ref();\n        let hex_str = hex.strip_prefix(\"0x\").unwrap_or(hex);\n\n        anyhow::ensure!(\n            hex_str.len() == 64,\n            \"Pool ID hex must be 64 characters (32 bytes), was {}\",\n            hex_str.len()\n        );\n\n        validate_hex_string(&format!(\"0x{hex_str}\"))?;\n\n        Ok(Self::PoolId(Ustr::from(&format!(\n            \"0x{}\",\n            hex_str.to_lowercase()\n        ))))\n    }\n\n    /// Returns the inner identifier value as a Ustr.\n    #[must_use]\n    pub fn inner(&self) -> Ustr {\n        match self {\n            Self::Address(s) | Self::PoolId(s) => *s,","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/defi/pool_identifier.rs#L123-L159","documentation":"`PoolIdentifier::from_pool_id_hex` builds a pool identifier from a hex string, which must be 64 hex characters (32 bytes) after an optional `0x` prefix. The library throws this when the stripped string length is not 64, since a 256-bit pool ID always encodes to exactly 64 hex chars.","triggerScenarios":"Calling `from_pool_id_hex` with a 40-char address hex, a truncated hex string, extra characters (spaces, checksum chars beyond hex), or a non-hex-length string.","commonSituations":"Pasting an EVM address (40 hex chars) where a pool ID is expected, copying partial hex from logs, or handling strings with whitespace/newlines from config files.","solutions":["Trim the input and confirm `len == 64` (after stripping `0x`) before calling.","If working with token/base addresses, use the Address constructor instead.","Validate the string is pure hex with `validate_hex_string` or a regex like `^0x[0-9a-fA-F]{64}$`.","Ensure config/env sources are not truncating or padding the value."],"exampleFix":"// before\nlet id = PoolIdentifier::from_pool_id_hex(token_address_hex)?; // 40 chars\n// after\nassert_eq!(hex_str.trim_start_matches(\"0x\").len(), 64);\nlet id = PoolIdentifier::from_pool_id_hex(pool_id_hex)?;","handlingStrategy":"validation","validationCode":"fn is_valid_pool_id_hex(s: &str) -> bool {\n    let h = s.strip_prefix(\"0x\").unwrap_or(s);\n    h.len() == 64 && h.chars().all(|c| c.is_ascii_hexdigit())\n}","typeGuard":"fn is_pool_id_hex(s: &str) -> bool { is_valid_pool_id_hex(s) }","tryCatchPattern":"match PoolIdentifier::from_pool_id_hex(input.trim()) {\n    Ok(id) => id,\n    Err(e) => { log::warn!(\"invalid pool id hex: {e}\"); return Err(e); }\n}","preventionTips":["Trim whitespace and normalize 0x prefix before validation","Distinguish 40-char address hex from 64-char pool id hex in your data model","Validate hex strings at config-load time, not at use time"],"tags":["defi","validation","hex-format","argument"],"backgroundTag":"invalid-argument-format","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}