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
- Choose an `AS OF` epoch/timestamp within the retained window — query a more recent version.
- Increase time-travel retention settings in the cluster config so desired epochs stay pinned longer, then re-run.
- 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`).
- 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
- Clamp AS OF timestamps to the configured time-travel retention window before querying.
- Increase retention config if historical reads are a product requirement.
- Record and honor `tonic::Code::OutOfRange` from the meta layer as 'version expired', not a bug.
- Monotonically age out cached historical versions on the client side.
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
- Change log retention miss: table {table_id}, epoch {epoch}
- time-travel version expired: table {table_id}, epoch {epoch}
- Wait epoch error: {0}
- Next epoch error: {0}
- Committed epoch mismatch: table {table_id}, committed_epoch
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/9bc3c65310ec8533.
Report an issue: GitHub.