risingwavelabs/risingwave · error · HummockError
bounded compaction requires Iceberg format V2 or V3
Error message
bounded compaction requires Iceberg format V2 or V3
What it means
Bounded compaction is validated against max_file_sequence_number, which is meaningful only for Iceberg format V2+ where sequence numbers exist on snapshots/data files. If the loaded table metadata reports format_version < V2 (i.e. V1), the runner fails closed rather than silently treating the boundary as meaningless.
Source
Thrown at src/storage/src/hummock/compactor/iceberg_compaction/iceberg_compactor_runner.rs:962
&& (pk_index_coordinated || compaction_kind.is_copy_on_write())
{
return Err(HummockError::compaction_executor(anyhow::anyhow!(
"bounded compaction is not supported for copy-on-write tasks"
)));
}
let branch = commit_branch(iceberg_config.r#type.as_str(), iceberg_config.write_mode);
let table = catalog
.load_table(&table_ident)
.await
.map_err(|e| HummockError::compaction_executor(e.as_report()))?;
if let Some(boundary) = max_file_sequence_number {
// An empty bounded plan is reported as `Drained`, so fail closed unless
// the loaded branch can prove that this fixed boundary is meaningful.
if table.metadata().format_version() < FormatVersion::V2 {
return Err(HummockError::compaction_executor(anyhow::anyhow!(
"bounded compaction requires Iceberg format V2 or V3"
)));
}
let head = table.metadata().snapshot_for_ref(&branch).ok_or_else(|| {
HummockError::compaction_executor(anyhow::anyhow!(
"bounded compaction branch {branch} has no snapshot"
))
})?;
if head.sequence_number() < boundary {
return Err(HummockError::compaction_executor(anyhow::anyhow!(
"bounded compaction head sequence {} is older than boundary {}",
head.sequence_number(),
boundary
)));
}
}
let planning_config = build_task_planning_config(View on GitHub (pinned to 6469eb736d)
Solutions
- Upgrade the table to Iceberg format V2 (rewrite metadata with a migration tool such as Spark's Iceberg migrations: CALL catalog.system.migrate_table / snapshot/update procedures).
- Recreate the iceberg sink/table with format-version = 2 (or 3) and backfill data.
- Submit the compaction without max_file_sequence_number if V1 must remain for now.
- Check the table's metadata.json format-version field to confirm what the catalog actually created.
Example fix
// before: table created with format-version = 1
// spark.sql CREATE TABLE ... TBLPROPERTIES('format-version'='1')
// after
// spark.sql CREATE TABLE ... TBLPROPERTIES('format-version'='2') Defensive patterns
Strategy: validation
Validate before calling
fn supports_bounded_compaction(table: &Table) -> bool {
table.metadata().format_version() >= FormatVersion::V2
} Prevention
- Create all Iceberg tables with format-version = 2 or 3.
- Migrate legacy V1 tables before enabling sequence-number-bounded compaction.
- Check metadata.json format-version when onboarding an externally created table.
When it happens
Trigger: A compaction request with max_file_sequence_number is submitted for an Iceberg table whose metadata format_version is 1 (created as a V1 table or downgraded), in create_task_execution.
Common situations: The Iceberg table was originally created in V1 format by external tooling and later pointed at RisingWave; user assumed V2 defaults but the catalog/table was created with format-version=1.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- bounded compaction branch {branch} has no snapshot
- bounded compaction head sequence {} is older than boundary {
- table {} not found
- register_table is not supported in mock catalog
- iceberg sink metadata should have schema_id
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/f13425038377d956.
Report an issue: GitHub.