{"record":{"id":"d2ab60411235d72d","repo":"quickwit-oss/tantivy","slug":"invalid-op-metadata-byte","errorCode":null,"errorMessage":"Invalid op metadata byte","messagePattern":"Invalid op metadata byte","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"columnar/src/columnar/writer/column_operation.rs","lineNumber":98,"sourceCode":"                    len: symbol_len,\n                }\n            }\n        };\n        minibuf.bytes[0] = column_op_metadata.to_code();\n        // +1 for the metadata\n        minibuf.len = 1 + column_op_metadata.len;\n        minibuf\n    }\n\n    /// Deserialize a column operation.\n    /// Returns None if the buffer is empty.\n    ///\n    /// Panics if the payload is invalid:\n    /// this deserialize method is meant to target in memory.\n    pub(super) fn deserialize(bytes: &mut &[u8]) -> Option<Self> {\n        let column_op_metadata_byte = pop_first_byte(bytes)?;\n        let column_op_metadata = ColumnOperationMetadata::try_from_code(column_op_metadata_byte)\n            .expect(\"Invalid op metadata byte\");\n        let symbol_bytes: &[u8];\n        (symbol_bytes, *bytes) = bytes.split_at(column_op_metadata.len as usize);\n        match column_op_metadata.op_type {\n            ColumnOperationType::NewDoc => {\n                let new_doc = u32::deserialize(symbol_bytes);\n                Some(ColumnOperation::NewDoc(new_doc))\n            }\n            ColumnOperationType::AddValue => {\n                let value = V::deserialize(symbol_bytes);\n                Some(ColumnOperation::Value(value))\n            }\n        }\n    }\n}\n\nimpl<T> From<T> for ColumnOperation<T> {\n    fn from(value: T) -> Self {\n        ColumnOperation::Value(value)","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/quickwit-oss/tantivy/blob/b5d8deb80c26924e6b007a5b1a7630f35ca64de4/columnar/src/columnar/writer/column_operation.rs#L80-L116","documentation":"ColumnOperation::deserialize parses an in-memory serialized column operation; the first byte is a metadata code that ColumnOperationMetadata::try_from_code must recognize. An unknown/invalid code hits .expect(\"Invalid op metadata byte\") and panics. Because deserialize targets in-memory buffers produced by the same code, an unrecognized byte means memory corruption, a desynced read position, or version skew between writer and reader of the operation format.","triggerScenarios":"Calling deserialize on a byte slice whose first byte is not a valid ColumnOperationMetadata code: reading at a wrong offset, byte buffer truncated/overwritten, or data written by a different version with new op codes.","commonSituations":"Hand-rolling reads over the column operation stream and losing byte alignment; concurrent mutation of the buffer; cross-version playback of operation logs.","solutions":["Verify the read cursor is exactly at an operation boundary; re-check preceding split_at/length arithmetic.","Ensure writer and reader code versions agree on ColumnOperationType/ColumnOperationMetadata codes.","Replace the expect with Option propagation (return None) if the format can legitimately contain unknown codes, for forward compatibility.","If the data comes from disk, re-check serialization/deserialization symmetry with round-trip tests."],"exampleFix":"// before\nlet column_op_metadata = ColumnOperationMetadata::try_from_code(byte).expect(\"Invalid op metadata byte\");\n// after\nlet column_op_metadata = ColumnOperationMetadata::try_from_code(byte).ok()?;","handlingStrategy":"validation","validationCode":"// Validate the byte slice begins with a known op code before deserialize\nfn op_code_known(bytes: &[u8]) -> bool {\n    bytes.first()\n        .map(|b| ColumnOperationMetadata::try_from_code(*b).is_ok())\n        .unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":"// panic-based; wrap and treat as data corruption\nlet op = std::panic::catch_unwind(|| ColumnOperation::deserialize(&mut bytes))\n    .unwrap_or_else(|_| panic-or-error);","preventionTips":["Keep op-code enums in sync across writer/reader versions","Round-trip test serialize/deserialize for every ColumnOperation variant","Track byte offsets explicitly to avoid cursor desync","Consider ok()? instead of expect for forward compatibility"],"tags":["rust","panic","deserialization","columnar"],"backgroundTag":"invalid-enum-code-deserialization","analyzedSha":"b5d8deb80c26924e6b007a5b1a7630f35ca64de4","analyzedAt":"2026-09-05T13:20:51.521Z","contentChangedAt":"2026-09-05T13:20:51.521Z","schemaVersion":2},"datasetVersion":"2026-09-12T17:17:11.597Z"}