linera-io/linera-protocol · error

trailing data after log fields ({} unexpected bytes)

Error message

trailing data after log fields ({} unexpected bytes)

What it means

decode_log enforces the log's declared payload boundary is consumed exactly: after address, topics list, and data string, log_data_buf must be empty (linera-bridge/src/proof/mod.rs:598). Trailing bytes mean the log list contains more than the three schema fields — a malformed log or a schema the parser does not know (e.g., a future EIP adding a fourth log field).

Source

Thrown at linera-bridge/src/proof/mod.rs:598

            .map_err(|e| anyhow!("invalid topic: {e}"))?;
        topics.push(topic);
    }

    // Decode log data (byte string)
    let data_header = alloy_rlp::Header::decode(&mut log_data_buf)
        .map_err(|e| anyhow!("invalid log data RLP: {e}"))?;
    ensure!(
        !data_header.list,
        "log data must be a byte string, not a list"
    );
    ensure!(
        log_data_buf.len() >= data_header.payload_length,
        "log data extends past log boundary"
    );
    let log_bytes = log_data_buf[..data_header.payload_length].to_vec();
    log_data_buf = &log_data_buf[data_header.payload_length..];

    ensure!(
        log_data_buf.is_empty(),
        "trailing data after log fields ({} unexpected bytes)",
        log_data_buf.len()
    );

    Ok(ReceiptLog {
        address,
        topics,
        data: log_bytes,
    })
}

#[cfg(test)]
mod tests {
    #![allow(clippy::cast_possible_truncation)]

    use std::str::FromStr;

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Hex-dump the trailing bytes: recognizable structure (e.g., another RLP item) indicates a schema extension — check the chain's EIP/fork status and update the parser to decode or deliberately skip the new field.
  2. Confirm the receipt proof verifies against the header root; if it does, the extra bytes are protocol content, not corruption.
  3. If the bytes are garbage, re-fetch the node — likely provider corruption.
  4. Keep parser and chain-preset versions locked together when deploying the bridge scanner.

Example fix

// before
ensure!(log_data_buf.is_empty(), "trailing data after log fields ({} unexpected bytes)", log_data_buf.len());

// after (post-fork schema with an optional 4th field: skip instead of failing)
if !log_data_buf.is_empty() {
    skip_rlp_item(&mut log_data_buf)?;
    ensure!(log_data_buf.is_empty(), "more than one extra log field");
}
Defensive patterns

Strategy: try-catch

Try / catch

match decode_receipt_logs(receipt_rlp) {
    Ok(logs) => logs,
    Err(e) if e.to_string().contains("trailing data after log fields") => {
        tracing::warn!(error = %e, "unknown extra log fields (fork?); rejecting node pending parser update");
        Vec::new()
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Decoding logs from a chain whose log entries carry extra fields beyond (address, topics, data); a corrupt node whose payload length overstates the content; fixtures that append extra bytes inside the log list.

Common situations: A hard fork extends the log schema and old parser binaries scan post-fork blocks; hand-built test logs with stray padding; trie nodes from an incompatible chain preset.

Related errors


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/4594970731bb3116. Report an issue: GitHub.