quickwit-oss/quickwit · error · io::Error (InvalidData)

unsupported split recovery metadata format version: {version

Error message

unsupported split recovery metadata format version: {version}

What it means

After the magic header validates, `SplitRecoveryMetadata::deserialize` reads a one-byte format version and compares it against SPLIT_RECOVERY_METADATA_FORMAT_VERSION. A valid envelope written by a different (older or newer) format version is rejected with InvalidData.

Source

Thrown at quickwit/quickwit-proto/src/metastore/mod.rs:69

            .expect("encoding a protobuf into a Vec should not fail");
        output
    }

    /// Deserializes split recovery metadata embedded in a split bundle.
    pub fn deserialize(mut bytes: &[u8]) -> io::Result<Self> {
        use prost::Message;

        if bytes.len() < SPLIT_RECOVERY_METADATA_HEADER_LEN
            || &bytes[..SPLIT_RECOVERY_METADATA_MAGIC.len()] != SPLIT_RECOVERY_METADATA_MAGIC
        {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                "invalid split recovery metadata magic number",
            ));
        }
        let version = bytes[SPLIT_RECOVERY_METADATA_MAGIC.len()];
        if version != SPLIT_RECOVERY_METADATA_FORMAT_VERSION {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                format!("unsupported split recovery metadata format version: {version}"),
            ));
        }
        bytes = &bytes[SPLIT_RECOVERY_METADATA_HEADER_LEN..];
        Self::decode(bytes).map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))
    }
}

#[cfg(test)]
mod split_recovery_metadata_tests {
    use super::SplitRecoveryMetadata;
    use crate::types::{DocMappingUid, IndexUid};

    #[test]
    fn test_split_recovery_metadata_roundtrip_and_unknown_fields() {
        let metadata = SplitRecoveryMetadata {
            split_id: "split-a".to_string(),

View on GitHub (pinned to a39730c5cd)

Solutions

  1. Align all Quickwit nodes to one version so the format version matches.
  2. Discard and regenerate recovery metadata created by the incompatible version.
  3. If a migration is needed, upgrade through the release that supports the old version rather than jumping directly.
  4. Inspect the version byte in the blob to identify which writer produced it.
Defensive patterns

Strategy: validation

Validate before calling

fn version_supported(bytes: &[u8]) -> bool {
    bytes.len() >= 6 && bytes[5] == SPLIT_RECOVERY_METADATA_FORMAT_VERSION
}

Try / catch

match SplitRecoveryMetadata::deserialize(&bytes) {
    Err(e) if e.to_string().contains("format version") => {
        // blob written by another Quickwit version: migrate or regenerate
    }
    other => other?,
}

Prevention

When it happens

Trigger: Deserializing a blob whose magic matches but whose version byte differs from the current SPLIT_RECOVERY_METADATA_FORMAT_VERSION — typically data written by another Quickwit release.

Common situations: Rolling upgrades/downgrades where nodes with different versions read each other's recovery metadata; restoring backups produced by an older release; replaying queued messages from a previous format.

Related errors


AI-assisted analysis of quickwit-oss/quickwit@a39730c5cd (2026-09-08). Data as JSON: /api/errors/ce22fa19579bf812. Report an issue: GitHub.