apache/superset · error · ChartNotFoundError

Chart not found.

Error message

Chart not found.

What it means

Raised as ChartNotFoundError by DeleteChartCommand.validate() when ChartDAO.find_by_ids does not return exactly one model per requested id. This means at least one chart id in the delete request does not exist (already deleted, wrong id, or filtered from view). Deletion of every chart in the batch is aborted before any row is touched.

Source

Thrown at superset/commands/chart/delete.py:55

logger = logging.getLogger(__name__)


class DeleteChartCommand(BaseCommand):
    def __init__(self, model_ids: list[int]):
        self._model_ids = model_ids
        self._models: Optional[list[Slice]] = None

    @transaction(on_error=partial(on_error, reraise=ChartDeleteFailedError))
    def run(self) -> None:
        self.validate()
        assert self._models
        ChartDAO.delete(self._models)

    def validate(self) -> None:
        # Validate/populate model exists
        self._models = ChartDAO.find_by_ids(self._model_ids)
        if not self._models or len(self._models) != len(self._model_ids):
            raise ChartNotFoundError()
        # Check there are no associated ReportSchedules
        if reports := ReportScheduleDAO.find_by_chart_ids(self._model_ids):
            report_names = [report.name for report in reports]
            raise ChartDeleteFailedReportsExistError(
                _(
                    "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 ChartForbiddenError() from ex

View on GitHub (pinned to f4587218dd)

Solutions

  1. Fetch the current list via GET /api/v1/chart/ and retry the delete with only ids that still exist.
  2. Treat 'not found' as success in idempotent delete scripts (catch 404 and continue).
  3. Check for trailing whitespace/type mismatches in ids passed to the API.

Example fix

# before
chart_dao_ids = [42]
client.delete('/api/v1/chart/', json={'ids': [42, 999]})

# after: verify existence first
existing = client.get('/api/v1/chart/?q={"filter":[{"col":"id","opr":"in","value":[42,999]}]}').json()
ids = [r['id'] for r in existing['result']]
client.delete('/api/v1/chart/', json={'ids': ids})
Defensive patterns

Strategy: validation

Validate before calling

existing = ChartDAO.find_by_ids(chart_ids)
if not existing or len(existing) != len(chart_ids):
    missing = set(chart_ids) - {c.id for c in existing or []}
    raise ValueError(f'charts not found: {missing}')

Try / catch

from superset.commands.chart.exceptions import ChartNotFoundError
try:
    DeleteChartCommand(ids).run()
except ChartNotFoundError:
    pass  # treat as already-deleted (idempotent delete)

Prevention

When it happens

Trigger: DELETE /api/v1/chart/ with a body id list containing a stale or nonexistent chart id; deleting a chart that another user/session already deleted; passing an internal integer id after charts were migrated/purged.

Common situations: Stale UI state listing a chart removed by someone else; scripts that cache chart ids across environments; double-submit of a delete request.

Related errors


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