databendlabs/databend · error · InvalidData

Invalid version

Error message

Invalid version

What it means

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.

Solutions

  1. Upgrade (or align) the Databend/plugin version with the one that wrote the semaphore permit entries.
  2. Clear or migrate the stale permit entries in the meta store so they are rewritten with CURRENT_VERSION.
  3. Verify the stored bytes are not corrupted (version byte flipped); restore meta from backup if corruption is confirmed.
  4. If intentional, bump the decode logic to accept/migrate the old version before returning the error.

Example fix

// before
let version = u8::decode(&mut r)?;
if version != CURRENT_VERSION {
    return Err(Error::new(io::ErrorKind::InvalidData, "Invalid version"));
}
// after
let version = u8::decode(&mut r)?;
if version > CURRENT_VERSION {
    return Err(Error::new(io::ErrorKind::InvalidData, "Invalid version"));
}
if version < CURRENT_VERSION {
    // migrate from legacy layout
}
Defensive patterns

Strategy: try-catch

Validate before calling

fn is_current_version_permit(buf: &[u8]) -> bool {
    buf.first() == Some(&CURRENT_VERSION)
}

Try / catch

match PermitEntry::decode(reader) {
    Err(e) if e.kind() == io::ErrorKind::InvalidData && e.to_string() == "Invalid version" => {
        // skip or migrate legacy record
        migrate_or_drop_record(key)?;
        Ok(None)
    }
    other => other,
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "cannot parse invalid wire-format data", "cannot unmarshal", "failed unmarshalling": protobuf unmarshal errors explained — this error's family across 10 libraries.

Related errors


AI-assisted analysis of databendlabs/databend@288d84d76e (2026-09-11). Data as JSON: /api/errors/6a16180c30b288e7. Report an issue: GitHub.

Appendix: source

Thrown at src/meta/plugins/semaphore/src/storage/permit_entry.rs:51

    pub id: String,
    pub permits: u64,
}

impl Encode for PermitEntry {
    fn encode<W: Write>(&self, mut w: W) -> Result<usize, io::Error> {
        let mut n = 0;
        n += CURRENT_VERSION.encode(&mut w)?;
        n += self.id.encode(&mut w)?;
        n += self.permits.encode(&mut w)?;
        Ok(n)
    }
}

impl Decode for PermitEntry {
    fn decode<R: Read>(mut r: R) -> Result<Self, io::Error> {
        let version = u8::decode(&mut r)?;
        if version != CURRENT_VERSION {
            return Err(Error::new(io::ErrorKind::InvalidData, "Invalid version"));
        }
        let id = Decode::decode(&mut r)?;
        let permits = Decode::decode(&mut r)?;

        Ok(PermitEntry { id, permits })
    }
}

impl fmt::Display for PermitEntry {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "PermitEntry(id:{}, n:{})", self.id, self.permits)
    }
}

impl PermitEntry {
    pub fn new(id: impl ToString, value: u64) -> Self {
        Self {
            id: id.to_string(),

View on GitHub (pinned to 288d84d76e)