risingwavelabs/risingwave · error
new item epoch {} does not exceed barrier offset epoch {}
Error message
new item epoch {} does not exceed barrier offset epoch {} What it means
`check_next_item_epoch` on a `TruncateOffset::Barrier` requires the new item's epoch to be strictly greater than the barrier's epoch, because everything after a barrier belongs to a later epoch. An equal-or-lesser epoch means pre-barrier data is arriving post-barrier.
Source
Thrown at src/connector/src/sink/log_store.rs:107
pub fn check_next_item_epoch(&self, epoch: u64) -> LogStoreResult<()> {
match self {
TruncateOffset::Chunk {
epoch: offset_epoch,
..
} => {
if epoch != *offset_epoch {
bail!(
"new item epoch {} does not match current chunk offset epoch {}",
epoch,
offset_epoch
);
}
}
TruncateOffset::Barrier {
epoch: offset_epoch,
} => {
if epoch <= *offset_epoch {
bail!(
"new item epoch {} does not exceed barrier offset epoch {}",
epoch,
offset_epoch
);
}
}
}
Ok(())
}
}
#[derive(Debug)]
pub enum LogStoreReadItem {
StreamChunk {
chunk: StreamChunk,
chunk_id: ChunkId,
},
Barrier {View on GitHub (pinned to 6469eb736d)
Solutions
- Drop or flush all pre-barrier items before recording the barrier offset
- Ensure items are sorted/filtered so post-barrier writes have epoch > barrier epoch
- Audit recovery paths for stale cursors replaying old epochs
Example fix
// before
store.check_next_item_epoch(item.epoch); // item.epoch <= barrier_epoch
// after
if item.epoch > barrier_epoch {
store.check_next_item_epoch(item.epoch);
} else {
item.drop_stale();
} Defensive patterns
Strategy: validation
Validate before calling
assert!(item_epoch > barrier_epoch, "post-barrier items must have epoch > barrier epoch");
Type guard
fn exceeds_barrier(epoch: u64, offset: &TruncateOffset) -> bool {
match offset {
TruncateOffset::Barrier { epoch: e } => epoch > *e,
_ => true,
}
} Try / catch
match offset.check_next_item_epoch(epoch) {
Err(_) => { /* drop stale pre-barrier item or replay from correct cursor */ }
Ok(()) => { /* write item */ }
} Prevention
- Flush all pre-barrier items before recording the barrier offset
- Persist cursor positions so recovery never replays pre-barrier epochs
- Validate epoch ordering in unit tests for barrier transitions
When it happens
Trigger: Calling `check_next_item_epoch(epoch)` while the current offset is `TruncateOffset::Barrier { epoch: offset_epoch }` with `epoch <= offset_epoch`; e.g. buffered items from before a barrier being written after the barrier was recorded.
Common situations: Out-of-order buffering in sink writers; replaying a queue from a stale cursor after recovery; barrier arrives while older-epoch items remain pending.
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
- new item epoch {} does not match current chunk offset epoch
- next offset {:?} should be later than current offset {:?}
- Division by zero
- Array error: {0}
- file_scan function is not supported in streaming mode
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/80761b332a5d629f.
Report an issue: GitHub.