risingwavelabs/risingwave · error · HummockError

Time-travel version expired: table {table_id}, epoch {epoch}

Error message

Time-travel version expired: table {table_id}, epoch {epoch}

What it means

Hummock reports that the requested time-travel version (a historical version of a table pinned at a specific epoch) has expired. Time-travel queries (`AS OF` semantics) read historical versions; the meta node (`src/meta/src/hummock/manager/time_travel.rs`) only retains versions within the configured safe retention window, and evicts older ones. When the requested `(table_id, epoch)` version is no longer pinned, the storage layer returns `time_travel_version_expired` via `HummockError::time_travel_version_expired`, which the meta layer maps to tonic `Code::OutOfRange`.

Source

Thrown at src/storage/src/hummock/error.rs:53

    #[error("Decode error: {0}")]
    DecodeError(String),
    #[error("ObjectStore failed with IO error: {0}")]
    ObjectIoError(
        #[from]
        #[backtrace]
        ObjectError,
    ),
    #[error("Meta error: {0}")]
    MetaError(String),
    #[error("SharedBuffer error: {0}")]
    SharedBufferError(String),
    #[error("Wait epoch error: {0}")]
    WaitEpoch(String),
    #[error("Next epoch error: {0}")]
    NextEpoch(String),
    #[error("Change log retention miss: table {table_id}, epoch {epoch}")]
    ChangeLogRetentionMiss { table_id: TableId, epoch: u64 },
    #[error("Time-travel version expired: table {table_id}, epoch {epoch}")]
    TimeTravelVersionExpired { table_id: TableId, epoch: u64 },
    #[error(
        "Committed epoch mismatch: table {table_id}, committed_epoch {committed_epoch}, read_epoch {read_epoch}"
    )]
    CommittedEpochMismatch {
        table_id: TableId,
        committed_epoch: u64,
        read_epoch: u64,
    },
    #[error("Barrier read is unavailable for now. Likely the cluster is recovering")]
    ReadCurrentEpoch,
    #[error("CompactionExecutor error: {0}")]
    CompactionExecutor(String),
    #[error("FileCache error: {0}")]
    FileCache(String),
    #[error("SstObjectIdTracker error: {0}")]
    SstObjectIdTrackerError(String),
    #[error("CompactionGroup error: {0}")]

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Choose an `AS OF` epoch/timestamp within the retained window — query a more recent version.
  2. Increase time-travel retention settings in the cluster config so desired epochs stay pinned longer, then re-run.
  3. Catch the error and map it to a user-facing 'version expired, choose a newer timestamp' message (meta layer already maps it to `tonic::Code::OutOfRange`).
  4. If only recent history is trimmed unexpectedly, verify GC/time-travel eviction is not over-aggressive for your workload.

Example fix

// before: any error is a hard failure
let v = time_travel_read(table_id, epoch)?;
// after: retry with the latest retained version
let v = match time_travel_read(table_id, epoch) {
    Err(e) if matches!(e.inner(), HummockErrorInner::TimeTravelVersionExpired { .. }) => {
        time_travel_latest_retained(table_id)?
    }
    other => other?,
};
Defensive patterns

Strategy: validation

Validate before calling

// Before issuing a time-travel read, ensure the target epoch/timestamp is within retention:
// let min_epoch = time_travel_client.oldest_retained_epoch(table_id);
// assert!(epoch >= min_epoch, "AS OF epoch {} expired", epoch);

Try / catch

match err.inner() {
    HummockErrorInner::TimeTravelVersionExpired { table_id, epoch } => {
        // surface a user-facing "version expired, pick a newer timestamp" error
    }
    _ => return Err(err),
}

Prevention

When it happens

Trigger: Calling a time-travel read API (e.g. `get_version`/`AS OF` lookup) against `meta::hummock::manager::time_travel::HummockManager` with an epoch older than the time-travel safe retention window; `Error::TimeTravelVersionExpired { table_id, epoch }` raised at src/meta/src/hummock/manager/time_travel.rs:568 when the version lookup returns `None`.

Common situations: Time-travel query issued for an `AS OF` timestamp/epoch older than `time_travel retention` config allows; retention window shortened via config while old history was already trimmed; client clock drift causing an epoch mapping outside the retained range.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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