{"record":{"id":"afce8cc09815fc1d","repo":"nautechsystems/nautilus_trader","slug":"failed-to-decode-burn-event-data-e","errorCode":null,"errorMessage":"Failed to decode burn event data: {e}","messagePattern":"Failed to decode burn event data: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/exchanges/parsing/uniswap_v3/burn.rs","lineNumber":89,"sourceCode":"        Some(topic) => {\n            let tick_upper_bytes: [u8; 32] = topic.as_ref().try_into()?;\n            i32::from_be_bytes(tick_upper_bytes[28..32].try_into()?)\n        }\n        None => anyhow::bail!(\"Missing tickUpper in topic3 when parsing burn event\"),\n    };\n\n    if let Some(data) = &log.data {\n        let data_bytes = data.as_ref();\n\n        // Validate if data contains 3 parameters of 32 bytes each\n        if data_bytes.len() < 3 * 32 {\n            anyhow::bail!(\"Burn event data is too short\");\n        }\n\n        // Decode the data using the BurnEventData struct\n        let decoded = match <BurnEventData as SolType>::abi_decode(data_bytes) {\n            Ok(decoded) => decoded,\n            Err(e) => anyhow::bail!(\"Failed to decode burn event data: {e}\"),\n        };\n\n        let pool_address = Address::from_slice(\n            log.address\n                .clone()\n                .expect(\"Contract address should be set in logs\")\n                .as_ref(),\n        );\n        let pool_identifier = PoolIdentifier::Address(Ustr::from(&pool_address.to_string()));\n        Ok(BurnEvent::new(\n            dex,\n            pool_identifier,\n            extract_block_number(log)?,\n            extract_transaction_hash(log)?,\n            extract_transaction_index(log)?,\n            extract_log_index(log)?,\n            owner,\n            tick_lower,","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/exchanges/parsing/uniswap_v3/burn.rs#L71-L107","documentation":"Raised by parse_burn_event_hypersync when alloy's ABI decoder fails to decode the Burn event data as BurnEventData, even though the 96-byte length check passed. The underlying alloy error is interpolated into the message. This means the bytes are long enough but do not match the Burn event ABI layout (types/values mismatch).","triggerScenarios":"Calling parse_burn_event_hypersync with data whose 96+ bytes do not decode as BurnEventData — e.g. data from a different event type with a similar shape, byte-swapped or truncated-but-padded data, or data encoded for an older/other contract version.","commonSituations":"Wrong topic filter capturing another event with 4 topics and >=96 data bytes; data hex string decoded with wrong endianness or with non-hex characters stripped in fixtures; a contract upgrade changing the data layout; corrupted payloads from a third-party indexer.","solutions":["Log the full {e} from the bail plus the data hex to identify the exact decoding failure (offset/length mismatch, invalid value)","Verify the topic0 filter matches the exact Burn event signature hash so only Burn-event data reaches the decoder","Check the BurnEventData type in the contract bindings matches the pool contract version actually emitting the log (regenerate bindings with alloy if the ABI changed)","Inspect the raw log's data field against the expected Burn layout (uint128 amount, uint256 amount0, uint256 amount1) on a block explorer"],"exampleFix":"// before\nErr(e) => anyhow::bail!(\"Failed to decode burn event data: {e}\"),\n// after (caller-side diagnostic + skip)\nmatch parse_burn_event_hypersync(log) {\n    Ok(ev) => { /* use ev */ }\n    Err(e) if e.to_string().contains(\"Failed to decode burn event data\") => {\n        tracing::warn!(data = ?log.data, \"non-Burn data layout; skipping: {e:#}\");\n        return Ok(None);\n    }\n    Err(e) => return Err(e),\n}","handlingStrategy":"try-catch","validationCode":"fn plausible_burn_data(data: &[u8]) -> bool {\n    data.len() == 96 && data.iter().all(|b| true) // length exact; deep check via re-encoding\n}\n// optionally re-encode the decoded struct and compare bytes to detect layout drift","typeGuard":null,"tryCatchPattern":"match parse_burn_event_hypersync(&log) {\n    Ok(ev) => handle(ev),\n    Err(e) if e.to_string().contains(\"Failed to decode burn event data\") => {\n        tracing::warn!(e = %e, data = ?log.data, \"ABI decode failed; quarantining log\");\n    }\n    Err(e) => return Err(e.into()),\n}","preventionTips":["Regenerate alloy bindings whenever the pool contract ABI changes","Log the full error chain ({e:#}) and raw data hex on decode failure","Pin the provider/contract version and verify topic0 hash against the Burn signature","Add round-trip tests: abi_encode(BurnEventData) then abi_decode must succeed"],"tags":["blockchain","uniswap-v3","abi","decoding"],"backgroundTag":"protobuf-unmarshal-failed","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"}