{"record":{"id":"9bc3c65310ec8533","repo":"risingwavelabs/risingwave","slug":"time-travel-version-expired-table-table-id-epo-9bc3c6","errorCode":null,"errorMessage":"Time-travel version expired: table {table_id}, epoch {epoch}","messagePattern":"Time-travel version expired: table (.+?), epoch (.+?)","errorType":"exception","errorClass":"HummockError","httpStatus":null,"severity":"error","filePath":"src/storage/src/hummock/error.rs","lineNumber":53,"sourceCode":"    #[error(\"Decode error: {0}\")]\n    DecodeError(String),\n    #[error(\"ObjectStore failed with IO error: {0}\")]\n    ObjectIoError(\n        #[from]\n        #[backtrace]\n        ObjectError,\n    ),\n    #[error(\"Meta error: {0}\")]\n    MetaError(String),\n    #[error(\"SharedBuffer error: {0}\")]\n    SharedBufferError(String),\n    #[error(\"Wait epoch error: {0}\")]\n    WaitEpoch(String),\n    #[error(\"Next epoch error: {0}\")]\n    NextEpoch(String),\n    #[error(\"Change log retention miss: table {table_id}, epoch {epoch}\")]\n    ChangeLogRetentionMiss { table_id: TableId, epoch: u64 },\n    #[error(\"Time-travel version expired: table {table_id}, epoch {epoch}\")]\n    TimeTravelVersionExpired { table_id: TableId, epoch: u64 },\n    #[error(\n        \"Committed epoch mismatch: table {table_id}, committed_epoch {committed_epoch}, read_epoch {read_epoch}\"\n    )]\n    CommittedEpochMismatch {\n        table_id: TableId,\n        committed_epoch: u64,\n        read_epoch: u64,\n    },\n    #[error(\"Barrier read is unavailable for now. Likely the cluster is recovering\")]\n    ReadCurrentEpoch,\n    #[error(\"CompactionExecutor error: {0}\")]\n    CompactionExecutor(String),\n    #[error(\"FileCache error: {0}\")]\n    FileCache(String),\n    #[error(\"SstObjectIdTracker error: {0}\")]\n    SstObjectIdTrackerError(String),\n    #[error(\"CompactionGroup error: {0}\")]","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/storage/src/hummock/error.rs#L35-L71","documentation":"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`.","triggerScenarios":"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`.","commonSituations":"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.","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."],"exampleFix":"// before: any error is a hard failure\nlet v = time_travel_read(table_id, epoch)?;\n// after: retry with the latest retained version\nlet v = match time_travel_read(table_id, epoch) {\n    Err(e) if matches!(e.inner(), HummockErrorInner::TimeTravelVersionExpired { .. }) => {\n        time_travel_latest_retained(table_id)?\n    }\n    other => other?,\n};","handlingStrategy":"validation","validationCode":"// Before issuing a time-travel read, ensure the target epoch/timestamp is within retention:\n// let min_epoch = time_travel_client.oldest_retained_epoch(table_id);\n// assert!(epoch >= min_epoch, \"AS OF epoch {} expired\", epoch);","typeGuard":null,"tryCatchPattern":"match err.inner() {\n    HummockErrorInner::TimeTravelVersionExpired { table_id, epoch } => {\n        // surface a user-facing \"version expired, pick a newer timestamp\" error\n    }\n    _ => return Err(err),\n}","preventionTips":["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."],"tags":["storage","hummock","time-travel","retention","epoch"],"backgroundTag":"value-out-of-range","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}