nautechsystems/nautilus_trader · error

Failed to decode swap event data: {e}

Error message

Failed to decode swap event data: {e}

What it means

After the length pre-check passes, parse_swap_event_hypersync decodes the log data with `<SwapEventData as SolType>::abi_decode`. If alloy's ABI decoder rejects the payload (wrong word count for dynamic decoding semantics, non-canonical encoding, or malformed hex-derived bytes), the error is wrapped as 'Failed to decode swap event data: {e}' with the underlying decoder message.

Source

Thrown at crates/adapters/blockchain/src/exchanges/parsing/pancakeswap_v3/swap.rs:76

/// # Panics
///
/// Panics if the contract address is not set in the log.
pub fn parse_swap_event_hypersync(dex: SharedDex, log: &HypersyncLog) -> anyhow::Result<SwapEvent> {
    validate_event_signature_hash("SwapEvent", SWAP_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();

        if data_bytes.len() < 7 * 32 {
            anyhow::bail!("Swap event data is too short");
        }

        let decoded = match <SwapEventData as SolType>::abi_decode(data_bytes) {
            Ok(decoded) => decoded,
            Err(e) => anyhow::bail!("Failed to decode swap 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(SwapEvent::new(
            dex,
            pool_identifier,
            extract_block_number(log)?,
            extract_transaction_hash(log)?,
            extract_transaction_index(log)?,
            extract_log_index(log)?,
            sender,
            recipient,
            decoded.amount0,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the wrapped alloy decoder message ({e}) — it usually states the exact word-count or byte-offset mismatch; correct the data source accordingly
  2. Confirm the data is exactly 0x + 448 hex chars for a PancakeSwap V3 Swap (7 words); strip or regenerate any extra/missing bytes at the source
  3. Re-fetch the log from HyperSync — storage/transit corruption of the data field is the most common cause
  4. If the pool is a fork with a different Swap layout, write a dedicated parser with the fork's field order instead of reusing SwapEventData

Example fix

// before: decoding whatever bytes arrived without normalization
let decoded = <SwapEventData as SolType>::abi_decode(data_bytes)?;

// after: validate the exact word layout before decoding
let hex = data.as_ref();
if hex.len() % 32 != 0 {
    anyhow::bail!("data is not a whole number of 32-byte words");
}
if hex.len() != 7 * 32 {
    anyhow::bail!("expected exactly 7 words for PancakeSwap V3 Swap, got {}", hex.len() / 32);
}
let decoded = <SwapEventData as SolType>::abi_decode(hex)
    .map_err(|e| anyhow::anyhow!("Failed to decode swap event data: {e}"))?;
Defensive patterns

Strategy: try-catch

Validate before calling

fn has_valid_swap_hex(data: Option<&HyperSyncData>) -> bool {
    data.map(|d| {
        let b = d.as_ref();
        b.len() == 7 * 32 && b.iter().all(|byte| true) // exact 7-word layout
    }).unwrap_or(false)
}

Type guard

fn is_exact_seven_word_data(log: &HypersyncLog) -> bool {
    log.data.as_ref().map(|d| d.as_ref().len() == 7 * 32).unwrap_or(false)
}

Try / catch

match parse_swap_event_hypersync(dex, &log) {
    Ok(event) => store(event),
    Err(e) if e.to_string().contains("Failed to decode") => {
        tracing::error!(err = %e, "ABI decode failed — inspect decoder message, re-fetch log from HyperSync");
        quarantine(log, e);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling parse_swap_event_hypersync with a PancakeSwap-topic log whose data is at least 224 bytes but is not a valid ABI encoding of (int256, int256, uint160, uint128, int24, uint128, uint128) — e.g. extra trailing bytes, non-numeric hex, or bytes corrupted in transit/storage.

Common situations: Logs fetched from a non-canonical or modified fork of PancakeSwap V3; custom indexing pipelines that uppercase/alter the data hex incorrectly; hand-edited test fixtures; decoding data that was sliced or padded at a non-32-byte boundary.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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