linera-io/linera-protocol · error
invalid log data RLP: {e}
Error message
invalid log data RLP: {e} What it means
After address and topics were consumed, the final field — the log data — does not start with a parsable RLP header. The data field must be an RLP byte string (list flag clear); a header decode failure here means the remaining bytes inside the log payload are truncated or misaligned.
Source
Thrown at linera-bridge/src/proof/mod.rs:586
ensure!(topics_header.list, "topics must be an RLP list");
ensure!(
log_data_buf.len() >= topics_header.payload_length,
"topics payload extends past log boundary"
);
let mut topics_data = &log_data_buf[..topics_header.payload_length];
log_data_buf = &log_data_buf[topics_header.payload_length..];
let mut topics = Vec::new();
while !topics_data.is_empty() {
let topic = <B256 as alloy_rlp::Decodable>::decode(&mut topics_data)
.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 {View on GitHub (pinned to 6c226ddcb3)
Solutions
- Pre-validate the entire log entry with alloy_primitives::Log::decode — it checks the three-field layout end to end.
- Confirm the encoder always emits the data byte string, even when empty (0x80).
- Check that topics_header.payload_length covers exactly all topics and nothing more.
- Regenerate the receipt and proof from the source chain.
Example fix
// before: data header read from whatever bytes remain
let data_header = alloy_rlp::Header::decode(&mut log_data_buf)
.map_err(|e| anyhow!("invalid log data RLP: {e}"))?;
// after: whole-entry validation first, custom parse second
use alloy_rlp::Decodable;
anyhow::ensure!(
alloy_primitives::Log::decode(&mut &log_entry_bytes[..]).is_ok(),
"log data field missing or misaligned — rejecting entry"
); Defensive patterns
Strategy: validation
Validate before calling
use alloy_rlp::Decodable;
fn log_has_valid_data_field(rlp: &[u8]) -> bool {
alloy_primitives::Log::decode(&mut &rlp[..]).is_ok() // data must be an RLP byte string
} Try / catch
Err(e) if e.to_string().contains("invalid log data RLP") => reject_proof(e), Prevention
- Always emit the data byte string in encoders, even for empty payloads (0x80).
- Keep the [address, topics, data] field order fixed across all producers.
When it happens
Trigger: decode_log with log_data_buf exhausted or starting mid-item after the topics slice: payload_length that stops before the data field, extra bytes appended inside the topics region, or a data field encoded as something other than a byte string header.
Common situations: Logs built without the data field at all (empty payloads must still be encoded as 0x80); encoders that put the data before the topics; truncation when copying proof blobs between systems.
Related errors
- invalid log RLP: {e}
- invalid log address: {e}
- invalid topics list RLP: {e}
- block header must be an RLP list
- receipt must be an RLP list
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/09d4db41cd543f8c.
Report an issue: GitHub.