{"record":{"id":"d3b613e61290f086","repo":"risingwavelabs/risingwave","slug":"catalog-object-has-no-database","errorCode":null,"errorMessage":"catalog object {} has no database","messagePattern":"catalog object (.+?) has no database","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/meta/src/controller/catalog/alter_op.rs","lineNumber":664,"sourceCode":"        }\n        if object_type == ObjectType::Table {\n            let table_type = Table::find_by_id(object_id.as_table_id())\n                .select_only()\n                .column(table::Column::TableType)\n                .into_tuple::<TableType>()\n                .one(&txn)\n                .await?\n                .ok_or_else(|| MetaError::catalog_id_not_found(\"table\", object_id))?;\n            if table_type == TableType::Internal {\n                return Err(MetaError::catalog_id_not_found(\"table\", object_id));\n            }\n        }\n        if obj.schema_id == Some(new_schema) {\n            return Ok(IGNORED_NOTIFICATION_VERSION);\n        }\n        let database_id = obj\n            .database_id\n            .ok_or_else(|| anyhow!(\"catalog object {} has no database\", object_id))?;\n\n        // Indexes are named schema objects rather than objects belonging to their primary table.\n        // Move them with a table explicitly, while subscriptions remain in their own schemas.\n        let mut objects = vec![obj];\n        if object_type == ObjectType::Table {\n            let index_ids = Index::find()\n                .select_only()\n                .column(index::Column::IndexId)\n                .filter(index::Column::PrimaryTableId.eq(object_id.as_table_id()))\n                .into_tuple::<IndexId>()\n                .all(&txn)\n                .await?;\n            objects.extend(\n                Object::find()\n                    .filter(\n                        object::Column::Oid\n                            .is_in(index_ids.into_iter().map(|id| id.as_object_id())),\n                    )","sourceCodeStart":646,"sourceCodeEnd":682,"githubUrl":"https://github.com/risingwavelabs/risingwave/blob/6469eb736d691e8e9b8a419a57edd6429ca77417/src/meta/src/controller/catalog/alter_op.rs#L646-L682","documentation":"alter_schema (moving a catalog object to a new schema) requires the object to belong to a database. If the loaded catalog object has `database_id == None` — a state that should be impossible for movable objects — it errors with `catalog object <id> has no database` instead of proceeding, protecting against corrupt or inconsistent catalog rows.","triggerScenarios":"Executing `ALTER ... SET SCHEMA` (alter_schema) on an object whose catalog row lacks a database_id — e.g. an object type that is not database-scoped, or corrupted/inconsistent metadata where the database link was lost.","commonSituations":"Metadata corruption after a failed upgrade or manual catalog edits; attempting schema moves on object kinds that were never assigned a database; bugs in connector/subscription object creation leaving the database link unset.","solutions":["Identify the object id from the message and inspect the catalog to see why its database_id is NULL.","Re-create the affected object with the correct schema/database and drop the broken one.","If metadata is corrupt after an upgrade or crash, restore from backup or use clean-data plus re-run DDL.","Report a bug if a normally database-scoped object (table/view/sink) hit this — it indicates an internal invariant violation."],"exampleFix":"// before: moving an object that may lack a database scope\nALTER TABLE mystery_object SET SCHEMA new_schema;\n// after: verify the object kind and scope first\n-- only database-scoped objects (tables, views, sinks) support SET SCHEMA\nSELECT object_id, database_id FROM catalog WHERE object_id = <id>; -- database_id must be non-null","handlingStrategy":"validation","validationCode":"-- only database-scoped objects can be moved between schemas\nSELECT object_id, object_type, database_id\nFROM catalog WHERE object_id = <id>;\n-- require database_id IS NOT NULL before ALTER ... SET SCHEMA","typeGuard":"fn movable_object(obj: &CatalogObject) -> Result<DatabaseId> {\n    obj.database_id\n        .ok_or_else(|| anyhow!(\"object {} is not database-scoped\", obj.id))\n}","tryCatchPattern":"match err {\n    e if e.to_string().contains(\"has no database\") => {\n        // recreate the object under the target schema; do not retry the ALTER\n    }\n    e => return Err(e.into()),\n}","preventionTips":["Only issue SET SCHEMA on tables/views/sinks/indexes, not on non-database-scoped object kinds.","After failed upgrades, validate catalog integrity before DDL.","Never hand-edit catalog tables; use supported DDL so database links stay consistent."],"tags":["meta","catalog","alter-schema","invariant"],"backgroundTag":"internal-invariant-violation","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"}