risingwavelabs/risingwave · warning
should not read changelog from MockWaitEpochStateStore
Error message
should not read changelog from MockWaitEpochStateStore
What it means
This is a deliberate `panic!` in the `MockWaitEpochStateStore` test double's `StateStoreChangeEventLog::iter_log` implementation. The mock exists only to wait for epoch releases (DML backpressure testing) and must never serve real reads; any call to iter_log signals the test or executor used the mock in an unsupported way. It is an internal invariant guard, not a runtime error users should see in production.
Solutions
- Do not exercise changelog reads in tests that use MockWaitEpochStateStore; restrict it to the wait-epoch/DML backpressure scenario.
- Use a real or recording state store implementation (e.g. MemoryStateStore) when the test must call iter_log.
- If the panic appears unexpectedly, trace which executor path reads the changelog and gate that path off in the test setup.
Example fix
// before let store = Arc::new(MockWaitEpochStateStore::new(...)); // executor under test reads changelog -> panics // after: use a store that supports changelog reads let store = MemoryStateStore::new();
Defensive patterns
Strategy: validation
Validate before calling
// assert the mock is only used where changelog reads never happen
assert!(
!test_exercises_changelog_reads,
"MockWaitEpochStateStore cannot serve iter_log; use MemoryStateStore"
); Prevention
- Reserve MockWaitEpochStateStore for wait-epoch/DML backpressure tests only.
- Prefer MemoryStateStore whenever reads or writes are exercised.
- Document the mock's supported surface at its definition.
- Fail fast in test setup if the executor under test performs changelog reads.
When it happens
Trigger: Any code path invoking `iter_log` on a `MockWaitEpochStateStore`, i.e. requesting a changelog iteration from the mock during a DML executor test.
Common situations: Writing or modifying a stream DML executor test that accidentally routes change-log reads through the mock; switching a test's state store from a real Hummock store to MockWaitEpochStateStore while the executor still exercises changelog reads.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- should not create local state from MockWaitEpochStateStore
- should not create vector writer from MockWaitEpochStateStore
- should not read snapshot from MockWaitEpochStateStore
- aggregate function is not supported
- All valid CDC connectors should have returned by now
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/deef98aeadeb05a3.
Report an issue: GitHub.
Appendix: source
Thrown at src/stream/src/executor/dml.rs:486
struct MockWaitEpochStateStore {
wait_epoch_called_tx: Arc<Mutex<Option<WaitEpochCallSender>>>,
wait_epoch_release_rx: Arc<tokio::sync::Mutex<Option<oneshot::Receiver<()>>>>,
}
impl StateStoreReadLog for MockWaitEpochStateStore {
type ChangeLogIter = PanicStateStoreIter<StateStoreReadLogItem>;
async fn next_epoch(&self, _epoch: u64, _options: NextEpochOptions) -> StorageResult<u64> {
panic!("should not read changelog from MockWaitEpochStateStore")
}
async fn iter_log(
&self,
_epoch_range: (u64, u64),
_key_range: TableKeyRange,
_options: ReadLogOptions,
) -> StorageResult<Self::ChangeLogIter> {
panic!("should not read changelog from MockWaitEpochStateStore")
}
}
impl StateStore for MockWaitEpochStateStore {
type Local = PanicStateStore;
type ReadSnapshot = PanicStateStore;
type VectorWriter = PanicStateStore;
async fn try_wait_epoch(
&self,
epoch: HummockReadEpoch,
options: TryWaitEpochOptions,
) -> StorageResult<()> {
if let Some(tx) = self.wait_epoch_called_tx.lock().unwrap().take() {
assert!(tx.send((epoch, options)).is_ok());
}
let rx = self.wait_epoch_release_rx.lock().await.take().unwrap();
rx.await.unwrap();View on GitHub (pinned to 6469eb736d)