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

dynamic protobuf decode error wrapped as io::Error…

Error message

dynamic protobuf decode error wrapped as io::Error (InvalidData) via map_err(|error| io::Error::new(io::ErrorKind::InvalidData, error))

What it means

After reading the version byte, `deserialize` zstd-decompresses the remainder and decodes it as a protobuf message with prost's `Self::decode`; any DecodeError is wrapped into io::Error(InvalidData) via map_err. The error therefore indicates valid envelope framing but corrupt/truncated compressed payload or a protobuf body that does not match the schema.

Solutions

  1. Inspect the inner prost DecodeError (chained as the io error's source) to identify the failing field.
  2. Regenerate the metadata by re-indexing or re-serializing from a known-good source.
  3. Confirm the quickwit-proto schema used by the reader matches the writer's schema/version.
  4. Check the storage object's integrity (ETag/checksum) against what the writer uploaded.
Defensive patterns

Strategy: try-catch

Try / catch

match SplitFieldsMetadata::deserialize(reader) {
    Err(e) if e.kind() == std::io::ErrorKind::InvalidData => {
        // check e.source(): prost DecodeError tells which field failed to decode
        regenerate_or_reindex()
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling deserialize on metadata whose zstd frame is truncated or corrupt, or whose decompressed bytes are not a valid serialized message — e.g. bytes written by a different schema version that still passes the version check, or bit-corrupted objects in storage.

Common situations: Corrupted objects after interrupted uploads; mismatched protobuf schema between writer and reader crates; storage returning wrong object content under the same key; manual payload manipulation in tooling.

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 quickwit-oss/quickwit@a39730c5cd (2026-09-08). Data as JSON: /api/errors/90d51382fbbf168e. Report an issue: GitHub.

Appendix: source

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

    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 {
        self.field_name
            .cmp(&other.field_name)
            .then_with(|| self.field_type.cmp(&other.field_type))
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    fn entry(field_name: &str) -> ListFieldsEntry {
        ListFieldsEntry {
            field_name: field_name.to_string(),

View on GitHub (pinned to a39730c5cd)