{"record":{"id":"9c05e09a48884f6a","repo":"nautechsystems/nautilus_trader","slug":"failed-to-decode-setfeeprotocol-event-data-e","errorCode":null,"errorMessage":"Failed to decode SetFeeProtocol event data: {e}","messagePattern":"Failed to decode SetFeeProtocol event data: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/exchanges/parsing/pancakeswap_v3/fee_protocol_update.rs","lineNumber":72,"sourceCode":"    dex: SharedDex,\n    log: &HypersyncLog,\n) -> anyhow::Result<FeeProtocolUpdateEvent> {\n    validate_event_signature_hash(\n        \"SetFeeProtocolEvent\",\n        FEE_PROTOCOL_UPDATE_EVENT_SIGNATURE_HASH,\n        log,\n    )?;\n\n    if let Some(data) = &log.data {\n        let data_bytes = data.as_ref();\n\n        if data_bytes.len() < 4 * 32 {\n            anyhow::bail!(\"SetFeeProtocol event data is too short\");\n        }\n\n        let decoded = match <SetFeeProtocolEventData as SolType>::abi_decode(data_bytes) {\n            Ok(decoded) => decoded,\n            Err(e) => anyhow::bail!(\"Failed to decode SetFeeProtocol 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\n        Ok(FeeProtocolUpdateEvent::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            decoded.fee_protocol0_new,","sourceCodeStart":54,"sourceCodeEnd":90,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/exchanges/parsing/pancakeswap_v3/fee_protocol_update.rs#L54-L90","documentation":"After the length check passes, the Hypersync parser decodes the raw bytes as `SetFeeProtocolEventData` using alloy's `SolType::abi_decode`; any decoding failure (wrong ABI shape, non-integer bytes, unexpected layout) is wrapped with this message including the underlying error. It means the data payload is 128+ bytes but does not conform to the expected SetFeeProtocol ABI (two uint8 fee fields in 32-byte words).","triggerScenarios":"Feeding `parse_fee_protocol_update_event_hypersync` a log whose data decodes differently than expected — e.g. a log from a different event that shares length characteristics, a contract with a modified SetFeeProtocol signature, or trailing extra fields that alloy's strict decoder rejects.","commonSituations":"See trigger scenarios.","solutions":["Confirm the log's topic0 equals the canonical SetFeeProtocol event selector before decoding.","Regenerate `SetFeeProtocolEventData` (sol! macro) from the exact ABI of the deployed PancakeSwap V3 pool/factory contracts.","Log `hex::encode(data_bytes)` alongside the error to inspect the actual payload and identify the emitting contract.","Skip non-conforming logs (return Ok(None)) instead of failing the whole ingestion batch."],"exampleFix":"// before\nlet decoded = match <SetFeeProtocolEventData as SolType>::abi_decode(data_bytes) {\n    Ok(d) => d,\n    Err(e) => anyhow::bail!(\"Failed to decode SetFeeProtocol event data: {e}\"),\n};\n// after\nif log.topic0() != SET_FEE_PROTOCOL_TOPIC {\n    return Ok(None);\n}\nlet decoded = <SetFeeProtocolEventData as SolType>::abi_decode(data_bytes)\n    .with_context(|| format!(\"SetFeeProtocol decode failed, data={}\", hex::encode(data_bytes)))?;","handlingStrategy":"try-catch","validationCode":"if log.topic0.as_deref() != Some(SET_FEE_PROTOCOL_TOPIC) {\n    return Ok(None);\n}\nif log.data.as_ref().map(|d| d.as_ref().len()).unwrap_or(0) < 128 {\n    return Ok(None);\n}","typeGuard":"fn is_set_fee_protocol_topic(log: &HyperSyncLog) -> bool {\n    log.topic0.as_deref() == Some(keccak256(\"SetFeeProtocol(uint8,uint8)\").to_string().as_str())\n}","tryCatchPattern":"let decoded = <SetFeeProtocolEventData as SolType>::abi_decode(data_bytes)\n    .map(Some)\n    .or_else(|e| {\n        tracing::warn!(\"SetFeeProtocol decode failed ({e}); data={}\", hex::encode(data_bytes));\n        Ok::<_, anyhow::Error>(None)\n    })?;","preventionTips":["Verify topic0 before decode; never rely on data length alone.","Regenerate ABI types via the sol! macro from the contract ABI JSON you actually index.","Include raw data hex in decode error context for forensics.","Skip bad logs per-record instead of failing the whole Hypersync batch."],"tags":["rust","anyhow","abi","event-parsing","pancakeswap-v3","decode-error"],"backgroundTag":"abi-decode-failed","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"}