{"record":{"id":"4922ab8cdbad6eed","repo":"apache/superset","slug":"database-not-found","errorCode":null,"errorMessage":"Database not found.","messagePattern":"Database not found\\.","errorType":"exception","errorClass":"DatabaseNotFoundError","httpStatus":404,"severity":"error","filePath":"superset/commands/database/delete.py","lineNumber":54,"sourceCode":"logger = logging.getLogger(__name__)\n\n\nclass DeleteDatabaseCommand(BaseCommand):\n    def __init__(self, model_id: int):\n        self._model_id = model_id\n        self._model: Optional[Database] = None\n\n    @transaction(on_error=partial(on_error, reraise=DatabaseDeleteFailedError))\n    def run(self) -> None:\n        self.validate()\n        assert self._model\n        DatabaseDAO.delete([self._model])\n\n    def validate(self) -> None:\n        # Validate/populate model exists\n        self._model = DatabaseDAO.find_by_id(self._model_id)\n        if not self._model:\n            raise DatabaseNotFoundError()\n        # Check there are no associated ReportSchedules\n\n        if reports := ReportScheduleDAO.find_by_database_id(self._model_id):\n            report_names = [report.name for report in reports]\n            raise DatabaseDeleteFailedReportsExistError(\n                _(\n                    \"There are associated alerts or reports: %(report_names)s\",\n                    report_names=\",\".join(report_names),\n                )\n            )\n        # Check if there are datasets for this database. ``self._model.tables``\n        # would now hide soft-deleted datasets (``SqlaTable`` inherits\n        # ``SoftDeleteMixin``, so the relationship lazy-load applies the\n        # visibility filter), letting a database whose datasets are all\n        # soft-deleted look empty and be hard-deleted while ``tables.database_id``\n        # rows still reference it. Count with the visibility filter bypassed so\n        # soft-deleted datasets still block the delete.\n        from superset.connectors.sqla.models import (  # pylint: disable=import-outside-toplevel","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset/commands/database/delete.py#L36-L72","documentation":"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.","triggerScenarios":"DELETE /api/v1/database/<id> with an id that was already deleted, never existed, or came from another environment.","commonSituations":"Double-delete races (two admins, or UI plus script); scripts with cached ids after environment rebuild; typos in the id.","solutions":["List databases (GET /api/v1/database/) and confirm the id before deleting.","Treat 404 as success in idempotent automation (the end state you wanted is already reached).","Refresh cached ids after exports/imports or environment resets."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"from superset.daos.database import DatabaseDAO\n\ndef database_exists(model_id: int) -> bool:\n    return DatabaseDAO.find_by_id(model_id) is not None","typeGuard":null,"tryCatchPattern":"from superset.commands.database.exceptions import DatabaseNotFoundError\n\ntry:\n    DeleteDatabaseCommand(model_id).run()\nexcept DatabaseNotFoundError:\n    pass  # already gone: treat delete as idempotent success","preventionTips":["Make deletion scripts idempotent: treat 404 as the desired end state.","Re-check the id via GET /api/v1/database/ before deleting in automation."],"tags":["database","not-found","delete","crud"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}