{"record":{"id":"f365429673de3862","repo":"nautechsystems/nautilus_trader","slug":"invalid-hex-e","errorCode":null,"errorMessage":"Invalid hex: {e}","messagePattern":"Invalid hex: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/rpc/log.rs","lineNumber":30,"sourceCode":"//  See the License for the specific language governing permissions and\n//  limitations under the License.\n// -------------------------------------------------------------------------------------------------\n\n//! Parses Ethereum JSON-RPC log entries.\n//!\n//! Converts `RpcLog` fields and hex strings to their domain types.\n\nuse alloy::primitives::Address;\nuse nautilus_core::hex;\nuse nautilus_model::defi::rpc::RpcLog;\n\n/// Decode hex string (with or without 0x prefix) to bytes.\n///\n/// # Errors\n///\n/// Returns an error if the hex string is invalid.\npub fn decode_hex(hex: &str) -> anyhow::Result<Vec<u8>> {\n    hex::decode(hex.trim_start_matches(\"0x\")).map_err(|e| anyhow::anyhow!(\"Invalid hex: {e}\"))\n}\n\n/// Parse hex string to u64.\n///\n/// # Errors\n///\n/// Returns an error if the hex string cannot be parsed as u64.\npub fn parse_hex_u64(hex: &str) -> anyhow::Result<u64> {\n    u64::from_str_radix(hex.trim_start_matches(\"0x\"), 16)\n        .map_err(|e| anyhow::anyhow!(\"Invalid hex u64: {e}\"))\n}\n\n/// Parse hex string to u32.\n///\n/// # Errors\n///\n/// Returns an error if the hex string cannot be parsed as u32.\npub fn parse_hex_u32(hex: &str) -> anyhow::Result<u32> {","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/rpc/log.rs#L12-L48","documentation":"The public helper `decode_hex` in the log adapter converts hex strings (with or without `0x` prefix) to bytes using the `hex` crate and wraps any decode failure in this error. It is surfaced when log-entry fields (addresses, topics, data) contain strings that are not valid hexadecimal.","triggerScenarios":"Calling `decode_hex` (directly or via `extract_address`, `extract_topic_bytes`, `extract_data_bytes`) with a string whose payload after stripping `0x` has odd length or contains non-hex characters — e.g. \"0xZZ12\", \"0x123\" (odd length), or an empty/non-hex data field.","commonSituations":"Handling logs from non-standard chains or mock servers with malformed data; off-by-one slicing producing odd-length substrings; passing UTF-8 text (method names, placeholders) instead of hex-encoded data; unpadded topic values copied from explorers.","solutions":["Validate the string: after stripping `0x`, it must be non-empty, even-length, and contain only [0-9a-fA-F].","Fix upstream slicing/indexing so you pass complete, even-length hex substrings.","For explorer-copied values, left-pad topics/addresses to the expected byte width before decoding.","Use `hex::decode` in a test to reproduce and identify the exact offending character/length."],"exampleFix":"// before\nlet bytes = decode_hex(data)?; // data = \"0x123\" (odd length) -> Invalid hex: Odd number of digits\n// after\nlet payload = data.trim_start_matches(\"0x\");\nanyhow::ensure!(!payload.is_empty() && payload.len() % 2 == 0, \"malformed hex data\");\nlet bytes = decode_hex(data)?;","handlingStrategy":"validation","validationCode":"fn is_valid_hex(s: &str) -> bool {\n    let body = s.trim_start_matches(\"0x\");\n    !body.is_empty() && body.len() % 2 == 0\n        && body.chars().all(|c| c.is_ascii_hexdigit())\n}\n// guard: if !is_valid_hex(log.data) { skip/log and continue }","typeGuard":"fn try_decode_hex(s: &str) -> Option<Vec<u8>> {\n    hex::decode(s.trim_start_matches(\"0x\")).ok()\n}","tryCatchPattern":"match decode_hex(&log.data) {\n    Err(e) if e.to_string().starts_with(\"Invalid hex:\") => {\n        tracing::warn!(data = %log.data, \"skipping log with malformed hex data\");\n        continue; // or record to a dead-letter list for later inspection\n    }\n    other => other,\n}","preventionTips":["Validate even length and hex charset before slicing/decoding log fields.","Left-pad topic/address strings from explorers to the expected width.","Sanitize mock/test fixtures to emit proper 0x-prefixed hex.","Add unit tests feeding odd-length and non-hex strings to decode_hex paths."],"tags":["hex","parsing","logs","decoding"],"backgroundTag":"invalid-hex-data","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"}