risingwavelabs/risingwave · error
since_timestamp is earlier than the retained changelog of up
Error message
since_timestamp is earlier than the retained changelog of upstream table {}: requested epoch {}, first retained checkpoint epoch {} What it means
The requested since_timestamp epoch is older than the earliest checkpoint epoch still retained in the upstream table's changelog. The required history has been trimmed, so a snapshot at that epoch cannot be produced.
Source
Thrown at src/meta/src/barrier/context/context_impl.rs:78
upstream_committed_epoch: u64,
table_change_log: &TableChangeLogs,
) -> MetaResult<SinceTimestampResolvedEpoch> {
let change_log = table_change_log.get(&table_id).ok_or_else(|| {
anyhow::anyhow!(
"no table changelog found for upstream table {} when resolving since_timestamp",
table_id
)
})?;
let Some(first_log) = change_log.first() else {
return Err(anyhow::anyhow!(
"empty table changelog found for upstream table {} when resolving since_timestamp",
table_id
)
.into());
};
let first_checkpoint_epoch = first_log.checkpoint_epoch;
if since_epoch < first_checkpoint_epoch {
return Err(anyhow::anyhow!(
"since_timestamp is earlier than the retained changelog of upstream table {}: requested epoch {}, first retained checkpoint epoch {}",
table_id,
since_epoch,
first_checkpoint_epoch,
)
.into());
}
if since_epoch >= upstream_committed_epoch {
return Err(anyhow::anyhow!(
"since_timestamp is not before the committed epoch of upstream table {}: requested epoch {}, committed epoch {}",
table_id,
since_epoch,
upstream_committed_epoch,
)
.into());
}
let latest_log = change_log.last().expect("checked non-empty");
if upstream_committed_epoch != latest_log.checkpoint_epoch {View on GitHub (pinned to 6469eb736d)
Solutions
- Re-create the snapshot backfill with a more recent since_timestamp
- Increase upstream changelog/log-store retention
- If full history is needed, rebuild the upstream MV or use a full refresh instead of timestamp backfill
Example fix
-- before CREATE ... FROM mv WITH (SNC_TIMESTAMP = 'very old timestamp'); -- after: use a recent timestamp within retained changelog CREATE ... FROM mv WITH (SNC_TIMESTAMP = now - interval '1 hour');
Defensive patterns
Strategy: validation
Validate before calling
if since_epoch < first_retained_checkpoint_epoch {
return Err("since_timestamp older than retained changelog; increase retention or use newer timestamp");
} Type guard
fn within_retained_range(since: u64, first: u64, committed: u64) -> bool {
since >= first && since < committed
} Try / catch
match create_snapshot_backfill(...).await {
Err(e) if e.contains("earlier than the retained changelog") => pick_newer_since_timestamp(),
other => other,
} Prevention
- Pick since_timestamps within changelog retention
- Increase log-store retention for long-lived history needs
- Prefer full rebuild when old history is required
When it happens
Trigger: resolve_since_timestamp_log_store_epoch with since_epoch < first_log.checkpoint_epoch — e.g. backfilling from an MV whose old changelogs have been trimmed by retention policies.
Common situations: Slow snapshot backfill created long after upstream data history aged out; short changelog retention in log store; replaying an old DDL script against aged data.
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
- no table changelog found for upstream table {} when resolvin
- since_timestamp is later than the latest changelog of upstre
- empty table changelog found for upstream table {} when resol
- since_timestamp is not before the committed epoch of upstrea
- since_timestamp is too new for upstream table {}: requested
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/400000407234499c.
Report an issue: GitHub.