linera-io/linera-protocol · error
invalid RLP item: {e}
Error message
invalid RLP item: {e} What it means
skip_rlp_item's Header::decode failed at the current cursor: the next bytes are not a valid RLP item header (string or list). This helper walks block headers (decode_block_header) and receipt prefixes (decode_receipt_logs), so the error means the byte stream diverges from RLP structure at that point — corruption, truncation, or misaligned cursor.
Source
Thrown at linera-bridge/src/proof/mod.rs:536
for (key, value) in &entries {
builder.add_leaf(*key, value);
}
let root = builder.root();
let proof_nodes = builder.take_proof_nodes();
let proof = proof_nodes
.matching_nodes_sorted(&target_key)
.into_iter()
.map(|(_, bytes)| bytes.to_vec())
.collect();
(root, proof)
}
/// Skips one RLP item (string or list) by reading its header and advancing past the payload.
fn skip_rlp_item(data: &mut &[u8]) -> Result<()> {
let header = alloy_rlp::Header::decode(data).map_err(|e| anyhow!("invalid RLP item: {e}"))?;
ensure!(
data.len() >= header.payload_length,
"not enough data to skip RLP item"
);
*data = &data[header.payload_length..];
Ok(())
}
/// Decodes a single log entry from RLP.
///
/// Enforces the declared payload boundary: after decoding address, topics, and data,
/// verifies that exactly `payload_length` bytes were consumed.
fn decode_log(data: &mut &[u8]) -> Result<ReceiptLog> {
let log_header =
alloy_rlp::Header::decode(data).map_err(|e| anyhow!("invalid log RLP: {e}"))?;
ensure!(log_header.list, "log must be an RLP list");
ensure!(
data.len() >= log_header.payload_length,View on GitHub (pinned to 6c226ddcb3)
Solutions
- Re-fetch the header/receipt from a trusted source and re-encode rather than patching bytes
- Verify the walking order matches the consensus field order for the chain type
- Dump the bytes around the failure offset to spot misalignment (previous payload_length vs actual item size)
Defensive patterns
Strategy: validation
Validate before calling
fn is_rlp_shaped(b: &[u8]) -> bool {
if b.is_empty() { return false; }
matches!(b[0], 0x80..=0xff) // any RLP prefix; 0x00..=0x7f is a single byte (valid item)
|| b[0] < 0x80
} Try / catch
match decode_receipt_logs(&receipt_rlp) {
Err(e) if e.to_string().contains("invalid RLP item") => {
// cursor misalignment or corruption: re-fetch the source data
}
other => other?,
} Prevention
- Re-fetch and re-encode headers/receipts rather than repairing bytes
- Verify field walking order matches the consensus layout for the chain type
- Log the failure offset to detect payload_length misalignment from upstream fields
When it happens
Trigger: Walking a block header or receipt where a previous field had a wrong payload_length (cursor misalignment), a truncated buffer, or non-RLP data passed as RLP. Note the follow-up ensure 'not enough data to skip RLP item' is the separate out-of-bounds case.
Common situations: Truncated or hex-corrupted bytes from storage or fixtures; version drift in header layouts between chains; skipping fields in the wrong order so the cursor lands mid-item.
Related errors
- invalid receipt RLP: {e}
- failed to skip receipt field {i}: {e}
- invalid logs list RLP: {e}
- invalid log RLP: {e}
- receipt must be an RLP list
AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22).
Data as JSON: /api/errors/727fcf16cf2e38ca.
Report an issue: GitHub.