quickwit-oss/quickwit · error

invalid recovery time range: start {start} is after end {end

Error message

invalid recovery time range: start {start} is after end {end}

What it means

Thrown by try_from_recovery_metadata when a split's recovery metadata has both a start and an end timestamp but start > end, making the inclusive time range unconstructible. The code only accepts a valid ordered range or a fully absent one.

Source

Thrown at quickwit/quickwit-metastore/src/split_metadata.rs:214

            node_id,
            doc_mapping_uid,
            partition_id,
            num_docs,
            uncompressed_docs_size_bytes,
            time_range_start_inclusive,
            time_range_end_inclusive,
            create_timestamp,
            tags,
            delete_opstamp,
            num_merge_ops,
            parent_split_ids,
            maturation_period_millis,
        } = recovery_metadata;
        let time_range = match (time_range_start_inclusive, time_range_end_inclusive) {
            (Some(start), Some(end)) if start <= end => Some(start..=end),
            (None, None) => None,
            (Some(start), Some(end)) => {
                bail!("invalid recovery time range: start {start} is after end {end}")
            }
            _ => bail!("recovery time range must contain both start and end"),
        };
        ensure!(
            !footer_offsets.is_empty(),
            "invalid recovery footer offsets"
        );
        let maturity = match maturation_period_millis {
            Some(maturation_period_millis) => SplitMaturity::Immature {
                maturation_period: Duration::from_millis(maturation_period_millis),
            },
            None => SplitMaturity::Mature,
        };
        let split_metadata = Self {
            split_id: split_id.into(),
            index_uid: index_uid.ok_or_else(|| anyhow::anyhow!("missing recovery index UID"))?,
            partition_id,
            source_id,

View on GitHub (pinned to a39730c5cd)

Solutions

  1. Fix the offending split metadata so start <= end, or remove the time range entirely (both fields None)
  2. Delete/re-ingest the affected split so new metadata is generated
  3. Restore the metastore data from backup

Example fix

// before
{"time_range_start_inclusive": 1700, "time_range_end_inclusive": 1600}
// after
{"time_range_start_inclusive": 1600, "time_range_end_inclusive": 1700}
Defensive patterns

Strategy: validation

Validate before calling

fn time_range_valid(start: Option<i64>, end: Option<i64>) -> bool {
    match (start, end) {
        (Some(s), Some(e)) => s <= e,
        (None, None) => true,
        _ => false,
    }
}

Type guard

fn valid_range(m: &RecoveryMetadata) -> bool {
    match (m.time_range_start_inclusive, m.time_range_end_inclusive) {
        (Some(s), Some(e)) => s <= e,
        (None, None) => true,
        _ => false,
    }
}

Try / catch

match SplitMetadata::try_from(recovery_meta) {
    Err(e) if e.to_string().contains("invalid recovery time range") => {
        error!("corrupted split metadata: {e}");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Loading or converting split metadata whose recovery metadata contains time_range_start_inclusive > time_range_end_inclusive, typically from corrupted or externally modified metadata records.

Common situations: Corrupted metastore rows after a crash; metadata files edited or copied between indexes with mismatched timestamps; clock-related data corruption.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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