risingwavelabs/risingwave · error
Dropping sink into table is not allowed for unmigrated table
Error message
Dropping sink into table is not allowed for unmigrated table {}. Please migrate it first. What it means
During drop_object, when dropping a sink whose target is a table, RisingWave checks that the target table is either being removed in the same transaction or has already been migrated (has_table_been_migrated). If the sink targets an unmigrated table, the drop is rejected with this error to avoid breaking the legacy table-sink coupling that the migration process is meant to resolve.
Source
Thrown at src/meta/src/controller/catalog/drop_op.rs:124
},
};
removed_objects.push(obj);
let mut removed_object_ids: HashSet<_> =
removed_objects.iter().map(|obj| obj.oid).collect();
for obj in &removed_objects {
if obj.obj_type == ObjectType::Sink {
let sink = Sink::find_by_id(obj.oid.as_sink_id())
.one(&txn)
.await?
.ok_or_else(|| MetaError::catalog_id_not_found("sink", obj.oid))?;
if let Some(target_table) = sink.target_table
&& !removed_object_ids.contains(&target_table.as_object_id())
&& !has_table_been_migrated(&txn, target_table).await?
{
return Err(anyhow::anyhow!(
"Dropping sink into table is not allowed for unmigrated table {}. Please migrate it first.",
target_table
).into());
}
}
}
// Load all objects that belong to the dropped objects before deletion. Cascaded rows are
// still needed for notifications and resource cleanup.
let root_objects = Object::find()
.filter(object::Column::Oid.is_in(removed_object_ids.iter().copied()))
.all(&txn)
.await?;
let belonging_objects =
get_belong_objects_by_ids(&txn, removed_objects.iter().map(|obj| obj.oid)).await?;
removed_object_ids.extend(belonging_objects.iter().map(|obj| obj.oid));
let mut objects_to_remove = root_objects.clone();
objects_to_remove.extend(belonging_objects.iter().cloned());View on GitHub (pinned to 6469eb736d)
Solutions
- Run the table migration for the target table first (as the message says), then drop the sink.
- Drop the target table and the sink together in the same operation/batch.
- Recreate the sink against a migrated (or external) target instead of the legacy table.
Example fix
// before DROP SINK my_sink; -- fails: table unmigrated // after -- migrate the table first, then: DROP SINK my_sink;
Defensive patterns
Strategy: validation
Validate before calling
-- before DROP SINK, confirm the target table is migrated or will be dropped too -- SQL: inspect sink targets and table state SHOW SINKS; -- identify sinks into tables -- ensure the table is migrated per your upgrade runbook before dropping the sink
Try / catch
match drop_result {
Err(e) if e.to_string().contains("unmigrated table") => {
run_table_migration(target_table)?;
drop_result = drop_sink(name).await; // retry once after migration
}
other => other?,
} Prevention
- Run required sink-into-table migrations as part of upgrade runbooks before DDL cleanup.
- Drop dependent sinks and their target tables in the same batch.
- Inventory legacy table-sinks after version upgrades and migrate them proactively.
When it happens
Trigger: DROP SINK on a sink created with 'INTO TABLE' where the target table still exists, is not part of the current removal batch (removed_object_ids), and has_table_been_migrated returns false.
Common situations: Upgrading clusters that require sink-into-table migration; attempting to clean up legacy sinks before running the required migration step; scripted teardown dropping sinks while their tables remain.
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
- no active frontend nodes found
- replace sink must not use snapshot backfill
- old sink job {} not found in barrier state
- replacement sink catalog requires a sink job
- old sink {} does not match replacement sink {}
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/57920caf5166d592.
Report an issue: GitHub.