{"record":{"id":"17b5cf3c03afc29d","repo":"Pumpkin-MC/Pumpkin","slug":"missing-inventory-transaction-type","errorCode":null,"errorMessage":"missing inventory transaction type","messagePattern":"missing inventory transaction type","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/pumpkin-protocol/src/bedrock/server/inventory_transaction.rs","lineNumber":187,"sourceCode":"    pub transaction_data: TransactionData,\n}\n\nimpl PacketRead for SInventoryTransaction {\n    fn read<R: Read>(buf: &mut R) -> Result<Self, Error> {\n        let legacy_request_id = VarInt::read(buf)?;\n\n        let has_legacy_slots = bool::read(buf)?;\n        let mut legacy_set_item_slots = Vec::new();\n        if has_legacy_slots {\n            let len = collection_length(buf, \"legacy item slot groups\")?;\n            legacy_set_item_slots.reserve(len);\n            for _ in 0..len {\n                legacy_set_item_slots.push(LegacySetItemSlot::read(buf)?);\n            }\n        }\n\n        if !bool::read(buf)? {\n            return Err(Error::new(\n                ErrorKind::InvalidData,\n                \"missing inventory transaction type\",\n            ));\n        }\n        let transaction_type = VarUInt::read(buf)?;\n\n        if !bool::read(buf)? {\n            return Err(Error::new(\n                ErrorKind::InvalidData,\n                \"missing inventory action data\",\n            ));\n        }\n        let actions_len = collection_length(buf, \"inventory actions\")?;\n        let mut actions = Vec::with_capacity(actions_len);\n        for _ in 0..actions_len {\n            actions.push(InventoryAction::read(buf)?);\n        }\n        let has_value = !actions.is_empty();","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/Pumpkin-MC/Pumpkin/blob/8d4639e25a57c15e47448ec327c780d41bbf2356/crates/pumpkin-protocol/src/bedrock/server/inventory_transaction.rs#L169-L205","documentation":"Thrown while decoding InventoryTransactionPacket when the optional-presence bool preceding the transaction type is false. The protocol signals each following field's presence with a boolean; the library requires the transaction type to always be present and rejects the packet otherwise.","triggerScenarios":"Triggered by InventoryTransactionPacket::read when bool::read(buf) returns false right before the transaction_type VarUInt is read.","commonSituations":"Stream desynchronization (a prior field misread consuming a wrong number of bytes), a client writing the packet without the presence flag, protocol version mismatch in field ordering.","solutions":["Check for earlier misalignment in the packet decode (actions/legacy slots lengths).","Ensure the client serializes the presence bool as true before the transaction type.","Compare protocol version field layouts between client and server.","Dump the raw packet bytes and hand-decode from the start to locate the desync."],"exampleFix":"// sender before: omitting presence flag\nwrite_varuint(buf, transaction_type)?;\n// after\nbuf.push(0x01); // presence bool: true\nwrite_varuint(buf, transaction_type)?;","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match InventoryTransactionPacket::read(buf) {\n    Err(e) if e.to_string().contains(\"missing inventory transaction type\") => {\n        log::warn!(\"transaction packet missing required type flag: {e}; dropping\");\n        // inspect stream alignment before blaming the client\n    }\n    other => other?,\n}","preventionTips":["Always write the presence bool (true) before the transaction type","Hand-decode raw bytes when this error appears; it usually signals earlier desync","Compare packet layout against the client's protocol version"],"tags":["bedrock","protocol","inventory","packet-decoding"],"backgroundTag":"missing-required-argument","analyzedSha":"8d4639e25a57c15e47448ec327c780d41bbf2356","analyzedAt":"2026-09-09T15:32:22.916Z","contentChangedAt":"2026-09-09T15:32:22.916Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}