{"record":{"id":"6a16180c30b288e7","repo":"databendlabs/databend","slug":"invalid-version","errorCode":null,"errorMessage":"Invalid version","messagePattern":"Invalid version","errorType":"validation","errorClass":"InvalidData","httpStatus":null,"severity":"error","filePath":"src/meta/plugins/semaphore/src/storage/permit_entry.rs","lineNumber":51,"sourceCode":"    pub id: String,\n    pub permits: u64,\n}\n\nimpl Encode for PermitEntry {\n    fn encode<W: Write>(&self, mut w: W) -> Result<usize, io::Error> {\n        let mut n = 0;\n        n += CURRENT_VERSION.encode(&mut w)?;\n        n += self.id.encode(&mut w)?;\n        n += self.permits.encode(&mut w)?;\n        Ok(n)\n    }\n}\n\nimpl Decode for PermitEntry {\n    fn decode<R: Read>(mut r: R) -> Result<Self, io::Error> {\n        let version = u8::decode(&mut r)?;\n        if version != CURRENT_VERSION {\n            return Err(Error::new(io::ErrorKind::InvalidData, \"Invalid version\"));\n        }\n        let id = Decode::decode(&mut r)?;\n        let permits = Decode::decode(&mut r)?;\n\n        Ok(PermitEntry { id, permits })\n    }\n}\n\nimpl fmt::Display for PermitEntry {\n    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {\n        write!(f, \"PermitEntry(id:{}, n:{})\", self.id, self.permits)\n    }\n}\n\nimpl PermitEntry {\n    pub fn new(id: impl ToString, value: u64) -> Self {\n        Self {\n            id: id.to_string(),","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/databendlabs/databend/blob/288d84d76e20a2f8f7173bda9691eb6ece301aa9/src/meta/plugins/semaphore/src/storage/permit_entry.rs#L33-L69","documentation":"PermitEntry (semaphore plugin storage) implements a versioned binary Decode trait. The first byte of the serialized record is a version tag; if it does not equal CURRENT_VERSION, decode refuses the record with io::ErrorKind::InvalidData 'Invalid version' rather than guessing at an incompatible layout.","triggerScenarios":"Calling PermitEntry::decode on bytes whose version byte differs from CURRENT_VERSION — e.g. records written by an older or newer plugin version, or arbitrary/garbage bytes being decoded as a permit entry.","commonSituations":"Upgrading or downgrading Databend while the semaphore plugin's on-disk meta records use a different schema version; corrupted meta storage where the version byte was overwritten; manually crafted test fixtures using the wrong version byte.","solutions":["Upgrade (or align) the Databend/plugin version with the one that wrote the semaphore permit entries.","Clear or migrate the stale permit entries in the meta store so they are rewritten with CURRENT_VERSION.","Verify the stored bytes are not corrupted (version byte flipped); restore meta from backup if corruption is confirmed.","If intentional, bump the decode logic to accept/migrate the old version before returning the error."],"exampleFix":"// before\nlet version = u8::decode(&mut r)?;\nif version != CURRENT_VERSION {\n    return Err(Error::new(io::ErrorKind::InvalidData, \"Invalid version\"));\n}\n// after\nlet version = u8::decode(&mut r)?;\nif version > CURRENT_VERSION {\n    return Err(Error::new(io::ErrorKind::InvalidData, \"Invalid version\"));\n}\nif version < CURRENT_VERSION {\n    // migrate from legacy layout\n}","handlingStrategy":"try-catch","validationCode":"fn is_current_version_permit(buf: &[u8]) -> bool {\n    buf.first() == Some(&CURRENT_VERSION)\n}","typeGuard":null,"tryCatchPattern":"match PermitEntry::decode(reader) {\n    Err(e) if e.kind() == io::ErrorKind::InvalidData && e.to_string() == \"Invalid version\" => {\n        // skip or migrate legacy record\n        migrate_or_drop_record(key)?;\n        Ok(None)\n    }\n    other => other,\n}","preventionTips":["Align plugin/schema versions across the cluster before rolling upgrades.","Store and check the record version before decoding legacy entries.","Add migration logic for old versions instead of failing hard when formats evolve."],"tags":["meta-service","semaphore-plugin","serialization","versioning"],"backgroundTag":"protobuf-unmarshal-failed","analyzedSha":"288d84d76e20a2f8f7173bda9691eb6ece301aa9","analyzedAt":"2026-09-11T11:29:36.208Z","contentChangedAt":"2026-09-11T11:29:36.208Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}