{"record":{"id":"93e18e009632c15d","repo":"risingwavelabs/risingwave","slug":"epoch-should-be-greater-than-prev-epoch","errorCode":null,"errorMessage":"epoch {} should be greater than prev epoch {}","messagePattern":"epoch (.+?) should be greater than prev epoch (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/stream/src/common/log_store_impl/kv_log_store/serde.rs","lineNumber":958,"sourceCode":"        let prev_epoch = match &self.stream_state {\n            StreamState::Uninitialized => unreachable!(\"should have init\"),\n            StreamState::BarrierEmitted { prev_epoch } => *prev_epoch,\n            StreamState::AllConsumingRow { curr_epoch }\n            | StreamState::BarrierAligning { curr_epoch, .. } => {\n                return if *curr_epoch != epoch {\n                    Err(anyhow!(\n                        \"epoch {} does not match with current epoch {}\",\n                        epoch,\n                        curr_epoch\n                    ))\n                } else {\n                    Ok(())\n                };\n            }\n        };\n\n        if prev_epoch >= epoch {\n            return Err(anyhow!(\n                \"epoch {} should be greater than prev epoch {}\",\n                epoch,\n                prev_epoch\n            ));\n        }\n\n        while let Some((stream_epoch, _)) = self.not_started_streams.last() {\n            if *stream_epoch > epoch {\n                // Current epoch has not reached the first epoch of\n                // the stream. Later streams must also have greater epoch, so break here.\n                break;\n            }\n            if *stream_epoch < epoch {\n                return Err(anyhow!(\n                    \"current epoch {} has exceeded the epoch {} of the stream that has not started\",\n                    epoch,\n                    stream_epoch\n                ));","sourceCodeStart":940,"sourceCodeEnd":976,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/stream/src/common/log_store_impl/kv_log_store/serde.rs#L940-L976","documentation":"Thrown by the same epoch validation routine when the incoming epoch is not strictly greater than the previous epoch recorded in `StreamState::BarrierEmitted { prev_epoch }`. Epochs must monotonically increase across barriers; reusing or decreasing an epoch would corrupt the ordering guarantees of the log store and downstream Hummock snapshots.","triggerScenarios":"Issuing a barrier (via the log store append path) whose `epoch <= prev_epoch`, i.e. after a barrier has already been emitted with an equal or larger epoch.","commonSituations":"Duplicate barrier injection (same barrier sent twice), a recovery path re-emitting an old epoch, meta node reassigning an epoch after failover without bumping it, or clock/epoch-generation logic producing repeated values.","solutions":["Ensure every barrier carries a strictly increasing epoch from the epoch provider (meta service); never reuse an epoch after emitting it.","Check for duplicate barrier sends in the barrier manager / actor graph.","During failover, confirm the new leader continues epoch allocation above all previously emitted epochs (e.g. persisted high-water mark).","Add an assertion/log where epochs are generated to catch non-monotonic allocation early."],"exampleFix":"// before\nlet epoch = last_emitted_epoch; // reused epoch\n// after\nlet epoch = last_emitted_epoch + 1; // strictly greater\n","handlingStrategy":"validation","validationCode":"// Rust: assert strictly increasing epochs before emitting a barrier\nfn ensure_monotonic(prev: u64, next: u64) -> Result<(), String> {\n    if next <= prev { return Err(format!(\"epoch {} must be > prev {}\", next, prev)); }\n    Ok(())\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always allocate epochs from the centralized epoch provider; never cache and reuse.","On failover, persist and reload the high-water epoch before allocating new ones.","Deduplicate barriers before appending so the same epoch is not emitted twice."],"tags":["streaming","epoch","monotonicity","barrier"],"backgroundTag":"invalid-state-transition","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}