risingwavelabs/risingwave · error

legacy checkpoint missing required field `version`

Error message

legacy checkpoint missing required field `version`

What it means

In the legacy (uncompressed, non-enveloped) checkpoint decode path, the PbHummockVersionCheckpoint must still carry a `version` field; its absence means the data predates any known checkpoint format and cannot be interpreted. decode_checkpoint_data fails fast instead of guessing the format.

Solutions

  1. Restore checkpoint data from a backup produced by a RisingWave version that writes the `version` field
  2. Verify the object actually is a Hummock version checkpoint (not another protobuf type stored by mistake)
  3. If the data is truly pre-versioning legacy state, re-bootstrap meta state instead of decoding it
  4. Check for mixed-version deployment issues (old nodes writing checkpoints read by new nodes)
Defensive patterns

Strategy: fallback

Validate before calling

// Before trusting restored data, check it is a versioned checkpoint
let probe = PbHummockVersionCheckpoint::decode(bytes.as_ref())?;
if probe.version.is_none() { /* treat as incompatible legacy data */ }

Type guard

fn is_legacy_unversioned(ckpt: &PbHummockVersionCheckpoint) -> bool { ckpt.version.is_none() }

Try / catch

match decode_checkpoint_data(bytes, size) {
    Err(e) if e.to_string().contains("legacy checkpoint missing required field `version`") => {
        tracing::warn!("pre-versioning checkpoint data; re-bootstrap meta state");
        Err(e)
    }
    other => other,
}

Prevention

When it happens

Trigger: decode_checkpoint_data falls back to the legacy path (envelope decode failed), decodes raw bytes as PbHummockVersionCheckpoint, and finds ckpt.version == None.

Common situations: Reading checkpoint data written by a very old RisingWave release before versioning existed; corrupted bytes that happen to decode but lack version; hand-restored checkpoint objects from incompatible backups.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/c199a2acbaec11f8. Report an issue: GitHub.

Appendix: source

Thrown at src/meta/src/hummock/manager/checkpoint.rs:176

            compressed_size = envelope.payload.len(),
            decompressed_size = decompressed.len(),
            compression_ratio =
                format!("{:.2}x", decompressed.len() as f64 / envelope.payload.len().max(1) as f64),
            checksum = format!("{expected:#x}"),
            "decoded compressed checkpoint"
        );
        return Ok(ckpt);
    }

    // Legacy uncompressed format
    tracing::info!(
        data_size,
        "decoding checkpoint in legacy uncompressed format"
    );
    let ckpt =
        PbHummockVersionCheckpoint::decode(data).context("failed to decode legacy checkpoint")?;
    if ckpt.version.is_none() {
        return Err(anyhow::anyhow!("legacy checkpoint missing required field `version`").into());
    }
    Ok(ckpt)
}

fn decompress_payload(
    algo: CheckpointCompressionAlgorithm,
    payload: &[u8],
) -> Result<std::borrow::Cow<'_, [u8]>> {
    use anyhow::Context;

    match algo {
        CheckpointCompressionAlgorithm::CheckpointCompressionUnspecified => Ok(payload.into()),
        CheckpointCompressionAlgorithm::CheckpointCompressionZstd => {
            Ok(zstd::stream::decode_all(payload)
                .map(std::borrow::Cow::Owned)
                .context("zstd decompression failed")?)
        }
        CheckpointCompressionAlgorithm::CheckpointCompressionLz4 => {

View on GitHub (pinned to 6469eb736d)