risingwavelabs/risingwave · error · Error

invalid epoch range: {start_epoch}..={end_epoch}

Error message

invalid epoch range: {start_epoch}..={end_epoch}

What it means

HummockMetaError::InvalidEpochRange indicates an epoch range supplied to a Hummock operation is malformed — for example start_epoch greater than end_epoch, or a range that fails sanity checks. The message renders the exact start..=end range rejected.

Source

Thrown at src/meta/src/hummock/error.rs:50

        #[source]
        #[backtrace]
        anyhow::Error,
    ),
    #[error(transparent)]
    ObjectStore(
        #[from]
        #[backtrace]
        ObjectError,
    ),
    #[error("compactor {0} is disconnected")]
    CompactorUnreachable(HummockContextId),
    #[error("compaction group error: {0}")]
    CompactionGroup(String),
    #[error("SST {0} is invalid")]
    InvalidSst(HummockSstableObjectId),
    #[error("invalid manual compaction option: {0}")]
    InvalidManualCompactionOption(String),
    #[error("invalid epoch range: {start_epoch}..={end_epoch}")]
    InvalidEpochRange { start_epoch: u64, end_epoch: u64 },
    #[error("time-travel version expired: table {table_id}, epoch {epoch}")]
    TimeTravelVersionExpired { table_id: TableId, epoch: u64 },
    #[error("time travel")]
    TimeTravel(
        #[source]
        #[backtrace]
        anyhow::Error,
    ),
    #[error(transparent)]
    Internal(
        #[from]
        #[backtrace]
        anyhow::Error,
    ),
}

impl Error {

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Ensure start_epoch <= end_epoch in the range being sent
  2. Check the code that derives epochs from timestamps — fix ordering/inversion
  3. Query current epoch (via meta) instead of using hardcoded or stale values
  4. Log the originating range and clamp/swap it before calling the API

Example fix

// before
let (start_epoch, end_epoch) = (100, 50);
// after
let (start_epoch, end_epoch) = (50, 100);
assert!(start_epoch <= end_epoch);
Defensive patterns

Strategy: validation

Validate before calling

if start_epoch > end_epoch {
    return Err(anyhow!("invalid epoch range {}..={}", start_epoch, end_epoch));
}

Type guard

fn valid_epoch_range(start: u64, end: u64) -> bool { start <= end }

Try / catch

match op_with_epoch_range(start, end).await {
    Err(HummockMetaError::InvalidEpochRange { start_epoch, end_epoch }) => {
        eprintln!("fix range: start {start_epoch} must be <= end {end_epoch}");
    }
    other => other?,
}

Prevention

When it happens

Trigger: APIs taking an epoch range (e.g. time travel queries, version ranges, GC by epoch) receive start_epoch > end_epoch or otherwise invalid bounds.

Common situations: Computing epoch ranges from timestamps with incorrect ordering; off-by-one in epoch arithmetic; stale client caches producing inverted ranges; unit tests passing placeholder epochs.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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