risingwavelabs/risingwave · error · Error
time-travel version expired: table {table_id}, epoch {epoch}
Error message
time-travel version expired: table {table_id}, epoch {epoch} What it means
HummockMetaError::TimeTravelVersionExpired signals that a time-travel read requested a table version at an epoch that has already been marked expired and pruned. Hummock retains historical versions only up to the configured retention window; beyond it the version is no longer readable.
Source
Thrown at src/meta/src/hummock/error.rs:52
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 {
pub fn retryable(&self) -> bool {
matches!(self, Error::MetaStore(_))View on GitHub (pinned to 6469eb736d)
Solutions
- Increase the time-travel version retention/TTV retention config on the meta node and retry
- Pick an epoch within the available retention window (check hummock version timelines via risectl)
- Refresh the epoch to a recent snapshot instead of a stale one
- Restore from backup/object store snapshot if the historical data is genuinely required
Defensive patterns
Strategy: fallback
Validate before calling
if let Some(available) = meta_client.time_travel_version(table_id, epoch)? {
if available.is_expired() { /* pick a newer epoch instead */ }
}
Type guard
fn version_expired(err: &HummockMetaError) -> Option<(TableId, u64)> {
if let HummockMetaError::TimeTravelVersionExpired { table_id, epoch } = err { Some((*table_id, *epoch)) } else { None }
}
Try / catch
match read_as_of(table_id, epoch).await {
Err(HummockMetaError::TimeTravelVersionExpired { .. }) => {
eprintln!("version expired; reading latest snapshot instead");
read_latest(table_id).await
}
other => other,
}
Prevention
- Configure sufficient time-travel version retention for your workload
- Resolve epochs close to query time, not long in advance
- Check version availability before long-running time-travel jobs
- Alert when retention approaches the oldest epoch consumers need
When it happens
Trigger: Querying `AS OF` / time travel for (table_id, epoch) where epoch is older than the retention period (hummock time-travel version retention), or after the version was expired and cleaned by GC.
Common situations: Backfill or audit queries against old snapshots; retention period shortened in config so previously readable epochs expire; long-running query reusing a stale epoch handle; Iceberg-export/time-travel consumers reading beyond TTL.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- time travel
- invalid time travel delta chain: delta {} has prev version {
- Time-travel version expired: table {table_id}, epoch {epoch}
- Cannot find the snapshot id in the iceberg table.
- inconsistent hummock version: expected {}, actual {}
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/974d3947f8cd02b3.
Report an issue: GitHub.