risingwavelabs/risingwave · info

Iceberg compaction maintenance was cleared for sink

Error message

Iceberg compaction maintenance was cleared for sink {}

What it means

This error is delivered to a manual compaction waiter when the sink's compaction maintenance is cleared (e.g. sink deletion or schedule teardown via clear/stop paths). The pending oneshot waiter is removed and resolved with this Err, and any scheduled task for the sink is cancelled, so the caller learns their manual compaction will never complete.

Solutions

  1. Treat it as expected cancellation if you dropped or recreated the sink; re-trigger compaction on the new sink
  2. Check whether another operator/admin cleared maintenance concurrently
  3. Re-issue the manual compaction once the sink's schedule is re-established
  4. Coordinate sink lifecycle operations with compaction operations to avoid racing them

Example fix

// before
let task_id = rx.await??; // Err: maintenance cleared
// after
match rx.await {
    Ok(Ok(task_id)) => Ok(task_id),
    Ok(Err(e)) if e.to_string().contains("maintenance was cleared") => {
        info!("compaction cancelled by sink teardown");
        Err(SinkCompactionCancelled)
    }
    r => r,
}
Defensive patterns

Strategy: try-catch

Try / catch

match rx.await {
    Ok(Ok(task_id)) => Ok(task_id),
    Ok(Err(e)) if e.to_string().contains("maintenance was cleared") => {
        info!("manual compaction cancelled by sink teardown; not an error if sink was dropped");
        Ok(CompactionOutcome::Cancelled)
    }
    other => other,
}

Prevention

When it happens

Trigger: A caller awaits the Receiver from start_manual_compaction while clear_compaction_state / sink teardown runs: the waiter is removed from manual_compaction_waiters, the scheduled task is cancelled, and the waiter receives this error.

Common situations: The Iceberg sink (materialized view/sink) is dropped while a manual compaction is pending; admin clears compaction maintenance; meta-side state cleanup after sink recreation.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11). Data as JSON: /api/errors/1e3ae9bd95e76292. Report an issue: GitHub.

Appendix: source

Thrown at src/meta/src/manager/iceberg_compaction/schedule.rs:1070

            .into()));
        }

        handles
    }

    pub fn clear_iceberg_maintenance_by_sink_id(&self, sink_id: SinkId) {
        let (task_to_cancel, waiter) = {
            let mut guard = self.inner.write();
            let task_to_cancel = Self::remove_sink_schedule(&mut guard, sink_id);
            guard.snapshot_expiration_sink_ids.remove(&sink_id);
            guard.manifest_rewrite_sink_ids.remove(&sink_id);
            let waiter = guard.manual_compaction_waiters.remove(&sink_id);
            (task_to_cancel, waiter)
        };
        self.cancel_scheduled_task_if_any(sink_id, task_to_cancel);

        if let Some(waiter) = waiter {
            let _ = waiter.send(Err(anyhow!(
                "Iceberg compaction maintenance was cleared for sink {}",
                sink_id
            )
            .into()));
        }
    }

    fn remove_sink_schedule(
        guard: &mut IcebergCompactionManagerInner,
        sink_id: SinkId,
    ) -> Option<ScheduledCompactionTask> {
        guard
            .sink_schedules
            .remove(&sink_id)
            .and_then(|track| track.scheduled_task())
    }

    fn cancel_scheduled_task_if_any(&self, sink_id: SinkId, task: Option<ScheduledCompactionTask>) {

View on GitHub (pinned to 6469eb736d)