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

unsupported split fields format version: {version_byte[0]}

Error message

unsupported split fields format version: {version_byte[0]}

What it means

ListFields-style split fields metadata is serialized with a single leading version byte. `deserialize` reads that byte and rejects any value other than FIELDS_METADATA_FORMAT_VERSION with InvalidData, since the rest of the wire format cannot be trusted to match the parser.

Source

Thrown at quickwit/quickwit-proto/src/search/mod.rs:256

impl ListFieldsMetadata {
    /// Serializes the entries: one version byte followed by the zstd-compressed protobuf
    /// encoding of `Self`.
    pub fn serialize(&self) -> Vec<u8> {
        let payload = self.encode_to_vec();
        let mut out = vec![FIELDS_METADATA_FORMAT_VERSION];
        zstd::stream::copy_encode(&payload[..], &mut out, FIELDS_METADATA_COMPRESSION_LEVEL)
            .expect("zstd encoding into `Vec<u8>` should not fail");
        out
    }

    /// Reads the format produced by [`Self::serialize`].
    pub fn deserialize<R: Read>(mut reader: R) -> io::Result<Self> {
        let mut version_byte = [0u8; 1];
        reader.read_exact(&mut version_byte)?;

        if version_byte[0] != FIELDS_METADATA_FORMAT_VERSION {
            return Err(io::Error::new(
                io::ErrorKind::InvalidData,
                format!(
                    "unsupported split fields format version: {}",
                    version_byte[0]
                ),
            ));
        }
        let mut zstd_decoder = zstd::stream::read::Decoder::new(reader)?;
        let mut decompressed = Vec::new();
        zstd_decoder.read_to_end(&mut decompressed)?;

        Self::decode(&decompressed[..])
            .map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))
    }
}

impl ListFieldsEntry {
    pub fn cmp_by_name_and_type(&self, other: &Self) -> Ordering {

View on GitHub (pinned to a39730c5cd)

Solutions

  1. Ensure the payload is the exact output of the matching SplitFieldsMetadata::serialize, version byte included.
  2. Use a Quickwit version compatible with the metadata format stored on the splits.
  3. Re-generate or re-index the splits whose metadata is in an unsupported format.
  4. Log/inspect the version byte value to identify the writer version.
Defensive patterns

Strategy: validation

Validate before calling

fn fields_version_ok(first_byte: u8) -> bool {
    first_byte == FIELDS_METADATA_FORMAT_VERSION
}

Try / catch

match SplitFieldsMetadata::deserialize(reader) {
    Err(e) if e.to_string().contains("format version") => {
        // incompatible writer version: re-index or migrate the split metadata
    }
    other => other?,
}

Prevention

When it happens

Trigger: Deserializing split fields metadata written by a different Quickwit version (different FIELDS_METADATA_FORMAT_VERSION), or feeding deserialize a payload without the version prefix (e.g. the raw zstd/protobuf body).

Common situations: Upgrading/downgrading Quickwit while old splits' field metadata persists in storage; manually reassembling the payload and dropping the version byte; writing custom tooling against the metadata format.

Related errors


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