risingwavelabs/risingwave · error

catalog object {} has no database

Error message

catalog object {} has no database

What it means

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.

Source

Thrown at src/meta/src/controller/catalog/alter_op.rs:664

        }
        if object_type == ObjectType::Table {
            let table_type = Table::find_by_id(object_id.as_table_id())
                .select_only()
                .column(table::Column::TableType)
                .into_tuple::<TableType>()
                .one(&txn)
                .await?
                .ok_or_else(|| MetaError::catalog_id_not_found("table", object_id))?;
            if table_type == TableType::Internal {
                return Err(MetaError::catalog_id_not_found("table", object_id));
            }
        }
        if obj.schema_id == Some(new_schema) {
            return Ok(IGNORED_NOTIFICATION_VERSION);
        }
        let database_id = obj
            .database_id
            .ok_or_else(|| anyhow!("catalog object {} has no database", object_id))?;

        // Indexes are named schema objects rather than objects belonging to their primary table.
        // Move them with a table explicitly, while subscriptions remain in their own schemas.
        let mut objects = vec![obj];
        if object_type == ObjectType::Table {
            let index_ids = Index::find()
                .select_only()
                .column(index::Column::IndexId)
                .filter(index::Column::PrimaryTableId.eq(object_id.as_table_id()))
                .into_tuple::<IndexId>()
                .all(&txn)
                .await?;
            objects.extend(
                Object::find()
                    .filter(
                        object::Column::Oid
                            .is_in(index_ids.into_iter().map(|id| id.as_object_id())),
                    )

View on GitHub (pinned to 6469eb736d)

Solutions

  1. Identify the object id from the message and inspect the catalog to see why its database_id is NULL.
  2. Re-create the affected object with the correct schema/database and drop the broken one.
  3. If metadata is corrupt after an upgrade or crash, restore from backup or use clean-data plus re-run DDL.
  4. Report a bug if a normally database-scoped object (table/view/sink) hit this — it indicates an internal invariant violation.

Example fix

// before: moving an object that may lack a database scope
ALTER TABLE mystery_object SET SCHEMA new_schema;
// after: verify the object kind and scope first
-- only database-scoped objects (tables, views, sinks) support SET SCHEMA
SELECT object_id, database_id FROM catalog WHERE object_id = <id>; -- database_id must be non-null
Defensive patterns

Strategy: validation

Validate before calling

-- only database-scoped objects can be moved between schemas
SELECT object_id, object_type, database_id
FROM catalog WHERE object_id = <id>;
-- require database_id IS NOT NULL before ALTER ... SET SCHEMA

Type guard

fn movable_object(obj: &CatalogObject) -> Result<DatabaseId> {
    obj.database_id
        .ok_or_else(|| anyhow!("object {} is not database-scoped", obj.id))
}

Try / catch

match err {
    e if e.to_string().contains("has no database") => {
        // recreate the object under the target schema; do not retry the ALTER
    }
    e => return Err(e.into()),
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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