nautechsystems/nautilus_trader · error

Failed to decode CollectProtocol event data: {e}

Error message

Failed to decode CollectProtocol event data: {e}

What it means

Raised by parse_fee_protocol_collect_event_hypersync when FeeProtocolCollectEventData::abi_decode fails on data that passed the 64-byte length check. The alloy error is embedded, meaning the two 32-byte words do not match the expected (uint256, uint256) layout.

Source

Thrown at crates/adapters/blockchain/src/exchanges/parsing/uniswap_v3/fee_protocol_collect.rs:77

        "CollectProtocol",
        FEE_PROTOCOL_COLLECT_EVENT_SIGNATURE_HASH,
        log,
    )?;

    let sender = extract_address_from_topic(log, 1, "sender")?;
    let recipient = extract_address_from_topic(log, 2, "recipient")?;

    if let Some(data) = &log.data {
        let data_bytes = data.as_ref();

        // Validate the data contains 2 parameters of 32 bytes each
        if data_bytes.len() < 2 * 32 {
            anyhow::bail!("CollectProtocol event data is too short");
        }

        let decoded = match <FeeProtocolCollectEventData as SolType>::abi_decode(data_bytes) {
            Ok(decoded) => decoded,
            Err(e) => anyhow::bail!("Failed to decode CollectProtocol event data: {e}"),
        };

        let pool_address = Address::from_slice(
            log.address
                .clone()
                .expect("Contract address should be set in logs")
                .as_ref(),
        );
        let pool_identifier = PoolIdentifier::Address(Ustr::from(&pool_address.to_string()));

        Ok(FeeProtocolCollectEvent::new(
            dex,
            pool_identifier,
            extract_block_number(log)?,
            extract_transaction_hash(log)?,
            extract_transaction_index(log)?,
            extract_log_index(log)?,
            sender,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read the embedded error to identify which word failed to decode as uint256
  2. Verify topic0 equals the canonical CollectProtocol signature hash
  3. Dump data_bytes as hex and decode with cast abi-decode to compare layouts
  4. Re-fetch logs with the correct event filter from HyperSync

Example fix

// before
let decoded = <FeeProtocolCollectEventData as SolType>::abi_decode(data_bytes)?;
// after
anyhow::ensure!(
    log.topics[0].as_deref() == Some(&COLLECT_PROTOCOL_TOPIC0),
    "not CollectProtocol: {:?}", log.topics.first()
);
let decoded = <FeeProtocolCollectEventData as SolType>::abi_decode(data_bytes)?;
Defensive patterns

Strategy: try-catch

Validate before calling

anyhow::ensure!(
    log.topics[0].as_deref() == Some(&COLLECT_PROTOCOL_TOPIC0),
    "unexpected event for CollectProtocol parser"
);
anyhow::ensure!(log.data.as_deref().map_or(false, |d| d.len() >= 64), "missing/truncated data");

Type guard

fn is_collect_protocol(log: &Log) -> bool {
    log.topics.first().and_then(|t| t.as_deref()) == Some(&COLLECT_PROTOCOL_TOPIC0)
        && log.data.as_deref().map_or(false, |d| d.len() >= 64)
}

Try / catch

let decoded = <FeeProtocolCollectEventData as SolType>::abi_decode(data_bytes)
    .with_context(|| format!("CollectProtocol decode failed; data={:?}", log.data.as_deref().map(hex::encode)))?;

Prevention

When it happens

Trigger: Data words from a different event layout decoded as CollectProtocol; extra ABI offset/pointer encoding from dynamic fields; corrupted data bytes from upstream conversion.

Common situations: Custom pool contracts emitting same-topic events with different payloads; stale adapter ABI vs contract upgrade; bugs in hex-to-bytes conversion of test fixtures.

Understand the failure class

Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/2184f20d2936b97a. Report an issue: GitHub.