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

  1. Drop/recreate the subscription or cursor so it references the new table version.
  2. Re-create the dropped table/MV (or its replacement) before consuming the cursor.
  3. Check rw_catalog.rw_tables for the table id and reconcile subscriptions against existing tables.
  4. 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

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


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