apache/superset · error · DatabaseNotFoundError

Database not found.

Error message

Database not found.

What it means

DatabaseNotFoundError raised in DeleteDatabaseCommand.validate (delete.py:54) when DatabaseDAO.find_by_id(self._model_id) returns nothing. The database id targeted by DELETE /api/v1/database/<id> does not exist in the metadata DB.

Source

Thrown at superset/commands/database/delete.py:54

logger = logging.getLogger(__name__)


class DeleteDatabaseCommand(BaseCommand):
    def __init__(self, model_id: int):
        self._model_id = model_id
        self._model: Optional[Database] = None

    @transaction(on_error=partial(on_error, reraise=DatabaseDeleteFailedError))
    def run(self) -> None:
        self.validate()
        assert self._model
        DatabaseDAO.delete([self._model])

    def validate(self) -> None:
        # Validate/populate model exists
        self._model = DatabaseDAO.find_by_id(self._model_id)
        if not self._model:
            raise DatabaseNotFoundError()
        # Check there are no associated ReportSchedules

        if reports := ReportScheduleDAO.find_by_database_id(self._model_id):
            report_names = [report.name for report in reports]
            raise DatabaseDeleteFailedReportsExistError(
                _(
                    "There are associated alerts or reports: %(report_names)s",
                    report_names=",".join(report_names),
                )
            )
        # Check if there are datasets for this database. ``self._model.tables``
        # would now hide soft-deleted datasets (``SqlaTable`` inherits
        # ``SoftDeleteMixin``, so the relationship lazy-load applies the
        # visibility filter), letting a database whose datasets are all
        # soft-deleted look empty and be hard-deleted while ``tables.database_id``
        # rows still reference it. Count with the visibility filter bypassed so
        # soft-deleted datasets still block the delete.
        from superset.connectors.sqla.models import (  # pylint: disable=import-outside-toplevel

View on GitHub (pinned to f4587218dd)

Solutions

  1. List databases (GET /api/v1/database/) and confirm the id before deleting.
  2. Treat 404 as success in idempotent automation (the end state you wanted is already reached).
  3. Refresh cached ids after exports/imports or environment resets.
Defensive patterns

Strategy: validation

Validate before calling

from superset.daos.database import DatabaseDAO

def database_exists(model_id: int) -> bool:
    return DatabaseDAO.find_by_id(model_id) is not None

Try / catch

from superset.commands.database.exceptions import DatabaseNotFoundError

try:
    DeleteDatabaseCommand(model_id).run()
except DatabaseNotFoundError:
    pass  # already gone: treat delete as idempotent success

Prevention

When it happens

Trigger: DELETE /api/v1/database/<id> with an id that was already deleted, never existed, or came from another environment.

Common situations: Double-delete races (two admins, or UI plus script); scripts with cached ids after environment rebuild; typos in the id.

Related errors


AI-assisted analysis of apache/superset@f4587218dd (2026-08-14). Data as JSON: /api/errors/4922ab8cdbad6eed. Report an issue: GitHub.