risingwavelabs/risingwave · error
since_timestamp is later than the latest changelog of…
Error message
since_timestamp is later than the latest changelog of upstream table {}: requested epoch {}, latest changelog epoch {} What it means
Binary search over the changelog failed to find a change-log entry at the target epoch, so the resolved snapshot epoch index is out of bounds. This indicates the requested epoch is beyond the latest retained changelog entry.
Solutions
- Use a since_timestamp within the retained changelog range
- Retry after the next barrier refreshes the changelog
- Check retention configuration and upstream progress
- Report a bug if the epoch was validated as within range beforehand
Defensive patterns
Strategy: validation
Validate before calling
let idx = search_index(change_log, since_epoch);
if idx >= change_log.len() {
return Err("since_timestamp beyond latest retained changelog entry");
} Type guard
fn index_in_bounds(log: &TableChangeLog, idx: usize) -> bool { idx < log.len() } Try / catch
match create_snapshot_backfill(...).await {
Err(e) if e.contains("later than the latest changelog") => retry_after_next_barrier(),
other => other,
} Prevention
- Keep since_epoch within [first, last] changelog checkpoints
- Refresh barrier state before resolution
- Watch for clock skew making timestamps too new
When it happens
Trigger: resolve_since_timestamp_log_store_epoch when the computed snapshot_epoch_index is >= change_log.len() (since_epoch later than all retained changelog entries), making change_log.get(index) return None.
Common situations: Since timestamp newer than the latest changelog entry due to clock skew; changelog trimmed; race where the barrier state changelog is stale relative to the caller's epoch.
Related errors
- no table changelog found for upstream table
- since_timestamp is earlier than the retained changelog of…
- empty table changelog found for upstream table
- since_timestamp is not before the committed epoch of…
- since_timestamp is too new for upstream table
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/fe7de6cc0eb770ff.
Report an issue: GitHub.
Appendix: source
Thrown at src/meta/src/barrier/context/context_impl.rs:120
)
.into());
}
// `binary_search_by_checkpoint_epoch` searches only by the checkpoint epoch
// of each changelog entry. An entry may still cover earlier non-checkpoint
// epochs, e.g. `{ non_checkpoint_epochs: [30, 35], checkpoint_epoch: 40 }`
// covers `(20, 40]` if the previous checkpoint is 20. For `since_epoch =
// 35`, the search returns `Err(index_of_40)`, and 40 is the snapshot epoch.
// For `since_epoch = 40`, it returns `Ok(index_of_40)`. In both cases, the
// resolved snapshot epoch is the least checkpoint epoch >= `since_epoch`.
let snapshot_epoch_index = match change_log.binary_search_by_checkpoint_epoch(since_epoch) {
Ok(index) => index,
Err(index) => index,
};
let snapshot_epoch = change_log
.get(snapshot_epoch_index)
.ok_or_else(|| {
anyhow::anyhow!(
"since_timestamp is later than the latest changelog of upstream table {}: requested epoch {}, latest changelog epoch {}",
table_id,
since_epoch,
upstream_committed_epoch,
)
})?
.checkpoint_epoch;
// A request inside the latest changelog entry may be smaller than
// `upstream_committed_epoch`, but still resolve to the latest checkpoint.
// That end-of-log case is not a usable historical snapshot epoch.
if snapshot_epoch >= upstream_committed_epoch {
return Err(anyhow::anyhow!(
"since_timestamp is too new for upstream table {}: requested epoch {}, resolved snapshot epoch {}, latest changelog epoch {}",
table_id,
since_epoch,
snapshot_epoch,
upstream_committed_epoch,
)View on GitHub (pinned to 6469eb736d)