risingwavelabs/risingwave · error
table id {dependent_table_id} has been dropped
Error message
table id {dependent_table_id} has been dropped What it means
When initializing a batch plan for a subscription cursor, the frontend checks that the dependent (state) table id still exists in the catalog version's state_table_info. If the key is missing, the table backing the subscription/cursor has been dropped, so the cursor cannot be planned. This guards the planner against reading a dangling table reference.
Source
Thrown at src/frontend/src/session/cursor_manager.rs:838
fn init_batch_plan_for_subscription_cursor(
rw_timestamp: Option<u64>,
dependent_table_id: TableId,
handler_args: HandlerArgs,
seek_pk_row: Option<Row>,
) -> Result<RwBatchQueryPlanResult> {
let session = handler_args.clone().session;
let table_catalog = session.get_table_by_id(dependent_table_id)?;
let context = OptimizerContext::from_handler_args(handler_args);
let version_id = {
let version = session.env.hummock_snapshot_manager.acquire();
let version = version.version();
if !version
.state_table_info
.info()
.contains_key(&dependent_table_id)
{
return Err(anyhow!("table id {dependent_table_id} has been dropped").into());
}
version.id
};
Self::create_batch_plan_for_cursor(
table_catalog,
&session,
context.into(),
rw_timestamp.map(|rw_timestamp| (rw_timestamp, rw_timestamp)),
version_id,
seek_pk_row,
)
}
async fn initiate_query(
rw_timestamp: Option<u64>,
dependent_table_id: TableId,
handler_args: HandlerArgs,
seek_pk_row: Option<Row>,View on GitHub (pinned to 6469eb736d)
Solutions
- Drop/recreate the subscription or cursor so it references the new table version.
- Re-create the dropped table/MV (or its replacement) before consuming the cursor.
- Check rw_catalog.rw_tables for the table id and reconcile subscriptions against existing tables.
- Remove orphaned subscriptions: inspect rw_catalog.rw_subscriptions and drop ones pointing at dropped tables.
Example fix
// before CREATE SUBSCRIPTION sub FROM mv; DROP MATERIALIZED VIEW mv; -- cursor plan fails: table dropped // after DROP SUBSCRIPTION sub; DROP MATERIALIZED VIEW mv; CREATE MATERIALIZED VIEW mv AS ...; CREATE SUBSCRIPTION sub FROM mv;
Defensive patterns
Strategy: validation
Validate before calling
-- before consuming a subscription cursor SELECT s.name FROM rw_catalog.rw_subscriptions s JOIN rw_catalog.rw_tables t ON s.dependent_table_id = t.table_id WHERE s.name = 'sub'; -- empty result means table dropped
Try / catch
match cursor.init_batch_plan() {
Err(e) if e.to_string().contains("has been dropped") => {
drop_subscription("sub");
recreate_subscription_on_new_table();
}
r => r,
} Prevention
- Drop subscriptions/cursors before dropping their backing tables.
- Automate DDL to cascade subscription cleanup.
- Monitor rw_catalog for orphaned subscriptions after MV recreation.
- Use idempotent subscription setup scripts keyed on table existence.
When it happens
Trigger: init_batch_plan_for_subscription_cursor() is invoked for a cursor/subscription whose dependent_table_id is absent from version.state_table_info — i.e. the table or MV feeding the subscription was dropped while the subscription cursor still existed.
Common situations: DROP TABLE/DROP MATERIALIZED VIEW executed while a subscription consumer still holds a cursor; stale subscription metadata after failover; schema-change or MV recreation replacing the state table id.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- dependent_table_id {dependent_table_id} not exists
- cannot find subscription with id {}
- subscription on table {} has invalid retention seconds {}
- distribution key {:?} must be a subset of primary key {:?}
- `catalog.type` must be set
AI-assisted analysis of risingwavelabs/risingwave@6469eb736d (2026-09-11).
Data as JSON: /api/errors/6e3cbaa20fae9c38.
Report an issue: GitHub.