risingwavelabs/risingwave · error
Iceberg metadata scan should not have input executors
Error message
Iceberg metadata scan should not have input executors
What it means
Same epoch-consistency check as error 2022 but for the update path: when decoding a `LogStoreOp::Update` (UpdateDelete/UpdateInsert pair), the row's `row_meta.epoch` must equal the read's `expected_epoch`. A mismatch means the stored update was tagged with a different epoch than the range being read, and the decoder refuses to emit the pair.
Source
Thrown at src/batch/executors/src/executor/iceberg_metadata_scan.rs:77
table,
self.metadata_type,
self.time_travel_info,
self.chunk_size,
) {
yield chunk?;
}
}
}
pub struct IcebergMetadataScanExecutorBuilder;
impl BoxedExecutorBuilder for IcebergMetadataScanExecutorBuilder {
async fn new_boxed_executor(
source: &ExecutorBuilder<'_>,
inputs: Vec<BoxedExecutor>,
) -> crate::error::Result<BoxedExecutor> {
ensure!(
inputs.is_empty(),
"Iceberg metadata scan should not have input executors"
);
let node = try_match_expand!(
source.plan_node().get_node_body().unwrap(),
NodeBody::IcebergMetadataScan
)?;
let metadata_type = match MetadataType::try_from(node.metadata_type)
.context("invalid Iceberg metadata type")?
{
MetadataType::Snapshots => IcebergMetadataTableType::Snapshots,
MetadataType::Manifests => IcebergMetadataTableType::Manifests,
MetadataType::Files => IcebergMetadataTableType::Files,
MetadataType::Unspecified => {
return Err(anyhow!("Iceberg metadata type is unspecified").into());
}
};
let time_travel_info = nodeView on GitHub (pinned to 6469eb736d)
Solutions
- Check the serialize path writes `row_meta.epoch` from the same barrier epoch used to compute expected_epoch on read.
- Confirm update rows are never split across epoch boundaries when buffered/flushed.
- Inspect the offending seq id's row_meta to detect corruption or miswritten epochs.
- Ensure the read range was selected for the epoch that actually contains the rows.
Defensive patterns
Strategy: validation
Validate before calling
// rust
// ensure updates are flushed within a single epoch
anyhow::ensure!(update_epoch == barrier_epoch, "update tagged epoch {} but flush epoch {}", update_epoch, barrier_epoch); Try / catch
// rust
match reader.deserialize_stream_chunk(start, end, expected_epoch).await {
Ok(chunk) => process(chunk),
Err(e) if e.to_string().contains("decoded epoch") => {
tracing::error!("update epoch mismatch, possible corruption: {e:#}");
// route to recovery instead of retrying the same read
}
Err(e) => return Err(e),
} Prevention
- Serialize update rows with the epoch of the barrier they belong to.
- Never split update pairs across epoch flush boundaries.
- Verify store contents after unclean shutdowns (checksums/scan).
When it happens
Trigger: Calling `deserialize_stream_chunk` on a range where a stored `LogStoreOp::Update` row has `row_meta.epoch != expected_epoch`. Thrown at serde.rs:489.
Common situations: Writer tagging update rows with a stale epoch across a barrier; reads whose expected epoch was computed from a different barrier; store corruption from an unclean shutdown mid-write.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- Chunk size can't be zero!
- Iceberg metadata type is unspecified
- GetChannelDeltaStatsExecutor should have no child!
- Iceberg metadata scan received a non-Iceberg connector
- file_scan_tasks must be Some
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/c96640a6e10a527c.
Report an issue: GitHub.