apache/superset · warning · DashboardNotFoundError
Dashboard not found.
Error message
Dashboard not found.
What it means
DashboardNotFoundError is raised by DeleteDashboardCommand.validate() when DashboardDAO.find_by_ids() returns no rows or fewer rows than the requested id list. At least one dashboard id in the bulk delete request does not exist (never existed, was hard-deleted, or was deleted concurrently).
Source
Thrown at superset/commands/dashboard/delete.py:72
raise DashboardForbiddenError() from ex
class DeleteDashboardCommand(BaseCommand):
def __init__(self, model_ids: list[int]):
self._model_ids = model_ids
self._models: Optional[list[Dashboard]] = None
@transaction(on_error=partial(on_error, reraise=DashboardDeleteFailedError))
def run(self) -> None:
self.validate()
assert self._models
DashboardDAO.delete(self._models)
def validate(self) -> None:
# Validate/populate model exists
self._models = DashboardDAO.find_by_ids(self._model_ids)
if not self._models or len(self._models) != len(self._model_ids):
raise DashboardNotFoundError()
# Check there are no associated ReportSchedules
if reports := ReportScheduleDAO.find_by_dashboard_ids(self._model_ids):
report_names = [report.name for report in reports]
raise DashboardDeleteFailedReportsExistError(
_(
"There are associated alerts or reports: %(report_names)s",
report_names=",".join(report_names),
)
)
# Check editorship
for model in self._models:
try:
security_manager.raise_for_editorship(model)
except SupersetSecurityException as ex:
raise DashboardForbiddenError() from ex
View on GitHub (pinned to f4587218dd)
Solutions
- Re-fetch the dashboard list and retry the delete with only ids that still exist.
- Treat 404 on delete as success in idempotent automation (the end state — dashboard absent — is achieved).
- Split large bulk deletes into per-id deletes so one missing id does not abort the whole batch.
Example fix
# before
DeleteDashboardCommand([10, 11, 999]).run() # 999 gone -> whole batch 404s
# after
existing = DashboardDAO.find_by_ids([10, 11, 999])
if existing:
DeleteDashboardCommand([d.id for d in existing]).run() Defensive patterns
Strategy: validation
Validate before calling
from superset.daos.dashboard import DashboardDAO
models = DashboardDAO.find_by_ids(ids)
alive_ids = [m.id for m in models]
if len(alive_ids) != len(ids):
logger.info('skipping missing ids: %s', set(ids) - set(alive_ids)) Try / catch
try:
DeleteDashboardCommand(ids).run()
except DashboardNotFoundError:
# treat as already deleted; optionally narrow and retry
retry_with_existing_ids_only() Prevention
- Re-query ids right before bulk delete.
- Split bulk deletes per id so one stale id cannot abort the batch.
- Treat delete-404 as success in idempotent automation.
When it happens
Trigger: DELETE /api/v1/dashboard/ with an id list containing a stale or nonexistent dashboard id; concurrent deletion by another user between listing and deleting; deleting a soft-deleted dashboard whose row the DAO no longer returns.
Common situations: Multi-select bulk delete in the UI after another admin already removed one dashboard; retrying a failed bulk delete where part of the batch succeeded; scripts with cached ids after a metadata DB restore.
Related errors
- Dashboard %(dashboard_id)s not found
- Chart not found.
- CSS template not found.
- Changing this Dashboard is forbidden
- There are associated alerts or reports: %(report_names)s
AI-assisted analysis of apache/superset@f4587218dd (2026-08-14).
Data as JSON: /api/errors/89bf8125f8943eda.
Report an issue: GitHub.