risingwavelabs/risingwave · error
Iceberg metadata type is unspecified
Error message
Iceberg metadata type is unspecified
What it means
Size-bound violation on the update path: decoding an update contributes two ops (`Op::UpdateDelete` and `Op::UpdateInsert`), and the running `ops.len()` exceeded `size_bound` after pushing both. This guards against oversized chunks consuming unbounded memory during decode.
Source
Thrown at src/batch/executors/src/executor/iceberg_metadata_scan.rs:92
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 = node
.time_travel
.as_ref()
.map(|time_travel| match time_travel {
TimeTravel::SnapshotId(snapshot_id) => IcebergTimeTravelInfo::Version(*snapshot_id),
TimeTravel::TimestampMs(timestamp_ms) => {
IcebergTimeTravelInfo::TimestampMs(*timestamp_ms)
}
});
let config = ConnectorProperties::extract(
WithOptionsSecResolved::new(node.with_properties.clone(), node.secret_refs.clone()),
false,
)?;
let ConnectorProperties::Iceberg(properties) = config else {
return Err(anyhow!("Iceberg metadata scan received a non-Iceberg connector").into());
};View on GitHub (pinned to 6469eb736d)
Solutions
- Make the write side count updates as two ops against size_bound when serializing chunks.
- Tighten the read range selection so it stops before exceeding size_bound ops.
- Increase size_bound consistently on both writer and reader if larger chunks are intended.
- Check for duplicated update entries in the KV store causing the count to inflate.
Example fix
// before
// writer counts each update as 1 op toward size_bound
if chunk_ops.len() > size_bound { flush(); }
// after
if chunk_ops.len() + 2 > size_bound { flush(); } // update = delete + insert
Defensive patterns
Strategy: validation
Validate before calling
// rust
// count an update pair as 2 ops when checking size_bound before write
anyhow::ensure!(pending_ops + 2 <= size_bound, "update pair would exceed size_bound {}", size_bound); Prevention
- Treat every update pair as two ops in size accounting on both write and read paths.
- Align size_bound configuration between writer and reader.
- Cap read ranges so decoded op count stays within bounds.
When it happens
Trigger: Calling `deserialize_stream_chunk` where decoded update pairs push total op count past `size_bound` (checked after `read_update(row_size)` and the two `ops.push` calls). Thrown at serde.rs:499.
Common situations: Write side packing many update pairs into one chunk while the reader uses a size_bound counted in single rows (each update counts as two); read ranges covering more than one chunk's worth of updates.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- GetChannelDeltaStatsExecutor should have no child!
- Iceberg metadata scan should not have input executors
- Chunk size can't be zero!
- 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/31fa9d129c806a28.
Report an issue: GitHub.