{"record":{"id":"24c04891945504d4","repo":"nautechsystems/nautilus_trader","slug":"topic-must-be-at-least-32-bytes-was","errorCode":null,"errorMessage":"Topic must be at least 32 bytes, was {}","messagePattern":"Topic must be at least 32 bytes, was (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/exchanges/parsing/core.rs","lineNumber":33,"sourceCode":"\n//! Shared core extraction functions for parsing event logs.\n//!\n//! These functions operate on raw bytes and are used by both HyperSync and RPC parsers\n//! to ensure consistent extraction logic.\n\nuse alloy::primitives::Address;\nuse nautilus_core::hex;\n\n/// Extract address from 32-byte topic (address in last 20 bytes).\n///\n/// In Ethereum event logs, indexed address parameters are stored as 32-byte\n/// values with the 20-byte address right-aligned (padded with zeros on the left).\n///\n/// # Errors\n///\n/// Returns an error if the byte slice is shorter than 32 bytes.\npub fn extract_address_from_bytes(bytes: &[u8]) -> anyhow::Result<Address> {\n    anyhow::ensure!(\n        bytes.len() >= 32,\n        \"Topic must be at least 32 bytes, was {}\",\n        bytes.len()\n    );\n    Ok(Address::from_slice(&bytes[12..32]))\n}\n\n/// Extract u32 from 32-byte topic (value in last 4 bytes, big-endian).\n///\n/// In Ethereum event logs, indexed numeric parameters are stored as 32-byte\n/// values with the number right-aligned in big-endian format.\n///\n/// # Errors\n///\n/// Returns an error if the byte slice is shorter than 32 bytes.\npub fn extract_u32_from_bytes(bytes: &[u8]) -> anyhow::Result<u32> {\n    anyhow::ensure!(\n        bytes.len() >= 32,","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/exchanges/parsing/core.rs#L15-L51","documentation":"extract_address_from_bytes expects an EVM log topic/data word: 32 bytes with the 20-byte address right-aligned in the last 20 bytes. It throws when the input slice is shorter than 32 bytes, since no full padded word is available. This guards against malformed log topics from the blockchain data source.","triggerScenarios":"Calling extract_address_from_bytes with a byte slice shorter than 32 bytes, e.g. a missing or truncated topic from a hypersync log, or passing a raw 20-byte address without 12 bytes of zero padding.","commonSituations":"A log event schema changed or the field index points at a topic that is absent/None; parsing a non-standard contract's event; passing data instead of topics (or vice versa).","solutions":["Check the log entry: ensure the topic field exists and is the full 32-byte padded word before calling","Pass a 20-byte address left-padded to 32 bytes if you have a raw address","Verify you are reading the correct topic index for the address field of this event","Confirm the emitting contract actually uses the standard Solidity event layout (bytes32 topics)"],"exampleFix":"// before\nlet addr = extract_address_from_bytes(topic.as_ref())?; // topic may be None/short\n// after\nensure!(topic.as_ref().map_or(false, |t| t.len() >= 32), \"missing or truncated topic\");\nlet addr = extract_address_from_bytes(topic.as_ref())?;","handlingStrategy":"validation","validationCode":"fn is_full_word(bytes: &[u8]) -> bool { bytes.len() >= 32 }","typeGuard":"fn as_topic_word(bytes: &[u8]) -> Option<&[u8; 32]> { bytes.get(..32)?.try_into().ok() }","tryCatchPattern":"match extract_address_from_bytes(topic) {\n    Ok(addr) => use(addr),\n    Err(e) if e.to_string().starts_with(\"Topic must be at least 32 bytes\") => skip_malformed_log(),\n    Err(e) => return Err(e),\n}","preventionTips":["Always validate topic presence and length before extracting address fields","Left-pad raw 20-byte addresses to 32 bytes before passing","Pin the event ABI/topic layout for the contracts you index","Add length assertions in tests using realistic log fixtures"],"tags":["ethereum","logs","parsing","validation"],"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-14T00:17:10.932Z"}