{"record":{"id":"b16feb098970282f","repo":"linera-io/linera-protocol","slug":"invalid-receipt-rlp-e","errorCode":null,"errorMessage":"invalid receipt RLP: {e}","messagePattern":"invalid receipt RLP: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"linera-bridge/src/proof/mod.rs","lineNumber":385,"sourceCode":"///\n/// Handles EIP-2718 typed receipts (type byte prefix < 0x80).\n///\n/// This variant exists because when tests build MPT tries\n/// with multiple receipts (e.g. test_build_receipt_proof_multiple_receipts),\n/// each receipt needs a distinct cumulative_gas_used to produce different\n/// RLP encodings. Without that, all empty-log receipts would be byte-identical,\n/// making the trie degenerate.\npub fn decode_receipt_logs(receipt_rlp: &[u8]) -> Result<Vec<ReceiptLog>> {\n    ensure!(!receipt_rlp.is_empty(), \"empty receipt RLP\");\n\n    let mut data: &[u8] = receipt_rlp;\n    // EIP-2718: if first byte < 0x80, it's a transaction type prefix\n    if data[0] < 0x80 {\n        data = &data[1..];\n    }\n\n    let list_header =\n        alloy_rlp::Header::decode(&mut data).map_err(|e| anyhow!(\"invalid receipt RLP: {e}\"))?;\n    ensure!(list_header.list, \"receipt must be an RLP list\");\n\n    // Limit reads to the receipt's declared payload.\n    ensure!(\n        data.len() >= list_header.payload_length,\n        \"receipt payload extends past available data\"\n    );\n    let mut data = &data[..list_header.payload_length];\n\n    // Skip: status (0), cumulative_gas_used (1), logs_bloom (2)\n    for i in 0..3 {\n        skip_rlp_item(&mut data).map_err(|e| anyhow!(\"failed to skip receipt field {i}: {e}\"))?;\n    }\n\n    // Decode the logs list\n    let logs_header =\n        alloy_rlp::Header::decode(&mut data).map_err(|e| anyhow!(\"invalid logs list RLP: {e}\"))?;\n    ensure!(logs_header.list, \"logs must be an RLP list\");","sourceCodeStart":367,"sourceCodeEnd":403,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-bridge/src/proof/mod.rs#L367-L403","documentation":"decode_receipt_logs failed to decode an RLP header for the receipt body: after optionally stripping the EIP-2718 type byte, the next bytes are not a valid RLP list header. The input is not structured as a receipt at all (or is corrupted). generate_deposit_proof maps this to ProofError::Permanent.","triggerScenarios":"Passing garbage or truncated bytes as receipt_rlp to decode_receipt_logs; bytes that are an RLP string rather than a list; a length prefix that exceeds the buffer. Unit tests exercise empty/single/multiple/typed receipts, so well-formed receipts never hit this.","commonSituations":"Feeding a hex string without decoding; feeding a transaction RLP instead of a receipt RLP; corrupted fixture or storage bytes.","solutions":["Feed the exact EIP-2718 canonical receipt bytes (as stored in the receipts trie), not a transaction or a JSON-decoded structure","Hex-decode before calling if the source data is a hex string","Log the first bytes (type prefix, list header) to see what shape the input actually has"],"exampleFix":"// before: passing a hex string\nlet logs = decode_receipt_logs(hex_str.as_bytes());\n\n// after: decode hex to bytes first\nlet bytes = hex::decode(hex_str)?;\nlet logs = decode_receipt_logs(&bytes)?;","handlingStrategy":"try-catch","validationCode":"fn is_receipt_shaped(b: &[u8]) -> bool {\n    if b.is_empty() { return false; }\n    let d = if b[0] < 0x80 { &b[1..] } else { &b[..] };\n    !d.is_empty() && (d[0] >= 0xc0) // typed/stripped payload must start with an RLP list prefix\n}","typeGuard":"fn decode_logs_safe(rlp: &[u8]) -> Option<Vec<ReceiptLog>> {\n    decode_receipt_logs(rlp).ok()\n}","tryCatchPattern":"match decode_receipt_logs(&receipt_rlp) {\n    Err(e) if e.to_string().contains(\"invalid receipt RLP\") => {\n        // reject the input; re-derive canonical bytes via Encodable2718\n    }\n    other => other?,\n}","preventionTips":["Only pass canonical EIP-2718 receipt bytes produced by Encodable2718","Hex-decode before calling when the source is a hex string","Reject empty or string-prefixed input before decoding"],"tags":["rlp","decoding","receipt","bridge","proof"],"backgroundTag":"rlp-decode-failed","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}