{"record":{"id":"6e3cbaa20fae9c38","repo":"risingwavelabs/risingwave","slug":"table-id-dependent-table-id-has-been-dropped","errorCode":null,"errorMessage":"table id {dependent_table_id} has been dropped","messagePattern":"table id (.+?) has been dropped","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/frontend/src/session/cursor_manager.rs","lineNumber":838,"sourceCode":"\n    fn init_batch_plan_for_subscription_cursor(\n        rw_timestamp: Option<u64>,\n        dependent_table_id: TableId,\n        handler_args: HandlerArgs,\n        seek_pk_row: Option<Row>,\n    ) -> Result<RwBatchQueryPlanResult> {\n        let session = handler_args.clone().session;\n        let table_catalog = session.get_table_by_id(dependent_table_id)?;\n        let context = OptimizerContext::from_handler_args(handler_args);\n        let version_id = {\n            let version = session.env.hummock_snapshot_manager.acquire();\n            let version = version.version();\n            if !version\n                .state_table_info\n                .info()\n                .contains_key(&dependent_table_id)\n            {\n                return Err(anyhow!(\"table id {dependent_table_id} has been dropped\").into());\n            }\n            version.id\n        };\n        Self::create_batch_plan_for_cursor(\n            table_catalog,\n            &session,\n            context.into(),\n            rw_timestamp.map(|rw_timestamp| (rw_timestamp, rw_timestamp)),\n            version_id,\n            seek_pk_row,\n        )\n    }\n\n    async fn initiate_query(\n        rw_timestamp: Option<u64>,\n        dependent_table_id: TableId,\n        handler_args: HandlerArgs,\n        seek_pk_row: Option<Row>,","sourceCodeStart":820,"sourceCodeEnd":856,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/frontend/src/session/cursor_manager.rs#L820-L856","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nCREATE SUBSCRIPTION sub FROM mv;\nDROP MATERIALIZED VIEW mv;\n-- cursor plan fails: table dropped\n\n// after\nDROP SUBSCRIPTION sub;\nDROP MATERIALIZED VIEW mv;\nCREATE MATERIALIZED VIEW mv AS ...;\nCREATE SUBSCRIPTION sub FROM mv;","handlingStrategy":"validation","validationCode":"-- before consuming a subscription cursor\nSELECT s.name FROM rw_catalog.rw_subscriptions s\nJOIN rw_catalog.rw_tables t ON s.dependent_table_id = t.table_id\nWHERE s.name = 'sub'; -- empty result means table dropped","typeGuard":null,"tryCatchPattern":"match cursor.init_batch_plan() {\n    Err(e) if e.to_string().contains(\"has been dropped\") => {\n        drop_subscription(\"sub\");\n        recreate_subscription_on_new_table();\n    }\n    r => r,\n}","preventionTips":["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."],"tags":["cursor","subscription","catalog","dropped-table"],"backgroundTag":"entity-not-found","analyzedSha":"6469eb736d691e8e9b8a419a57edd6429ca77417","analyzedAt":"2026-09-11T21:06:21.487Z","contentChangedAt":"2026-09-11T21:06:21.487Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}