risingwavelabs/risingwave · error · anyhow::Error
truncate offset {:?} but prev truncate offset is {:?}
Error message
truncate offset {:?} but prev truncate offset is {:?} What it means
Guard in the in-memory log store's truncate: the requested truncate offset is not strictly newer than the previously applied truncate offset (it is <= it). Truncation must monotonically advance; a stale or duplicated truncate request indicates a bug in the caller and returns this error.
Source
Thrown at src/stream/src/common/log_store_impl/in_mem.rs:235
LogStoreReadItem::Barrier {
is_checkpoint: options.is_checkpoint,
new_vnode_bitmap: options.new_vnode_bitmap,
is_stop: options.is_stop,
schema_change: options.schema_change,
},
))
}
},
None => Err(anyhow!("end of log stream")),
},
AwaitingTruncate { .. } => std::future::pending().await,
}
}
fn truncate(&mut self, offset: TruncateOffset) -> LogStoreResult<()> {
// check the truncate offset is higher than prev truncate offset
if self.truncate_offset >= offset {
return Err(anyhow!(
"truncate offset {:?} but prev truncate offset is {:?}",
offset,
self.truncate_offset
));
}
// check the truncate offset does not exceed the latest possible offset
if offset > self.latest_offset {
return Err(anyhow!(
"truncate at {:?} but latest offset is {:?}",
offset,
self.latest_offset
));
}
if let AwaitingTruncate {
sealed_epoch,
next_epoch,View on GitHub (pinned to 6469eb736d)
Solutions
- Ensure the truncation offset is derived from the minimum consumed offset and is monotonic
- Guard callers to skip truncate when offset <= current truncate offset
- Inspect epoch/consumption tracking for double-truncate races
Example fix
// before
log_store.truncate(offset).await?;
// after
if offset > current_truncate_offset {
log_store.truncate(offset).await?;
} Defensive patterns
Strategy: validation
Validate before calling
fn should_truncate(offset: u64, prev_truncate_offset: u64) -> bool {
offset > prev_truncate_offset
} Try / catch
if offset > current_truncate_offset {
log_store.truncate(offset).await?;
} Prevention
- Compute truncate offsets from min consumed epoch monotonically
- Deduplicate truncate requests among competing components
- Log skip-truncate decisions to detect stale offset computation
When it happens
Trigger: truncate(offset) invoked when self.truncate_offset >= offset, i.e. a duplicate or out-of-order truncate request.
Common situations: Bugs in min-working-epoch tracking that compute a stale truncate offset, multiple components racing to truncate, or recovery replaying an old truncation.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- truncate at {:?} but latest offset is {:?}
- Filter can only receive bool array
- end of log stream
- unable to send sealed epoch
- should not call rewind on it
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/d241072b230a472f.
Report an issue: GitHub.