apache/superset · error · ChartDeleteFailedReportsExistError

There are associated alerts or reports: %(report_names)s

Error message

There are associated alerts or reports: %(report_names)s

What it means

Raised as ChartDeleteFailedReportsExistError when ReportScheduleDAO.find_by_chart_ids finds at least one alert or report schedule that renders the chart being deleted. Superset blocks the delete to keep scheduled alerts/reports from silently breaking, and the message lists the offending report names.

Source

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

    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. Open Alerts & Reports in the UI, find the schedules named in the error, and either delete them or repoint them to another chart.
  2. Or via API: GET /api/v1/report/?q=... to find schedules referencing the chart, then DELETE them.
  3. Retry the chart delete once no ReportSchedule references the chart ids.

Example fix

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

# after: remove blocking schedules first
reports = client.get('/api/v1/report/').json()
# find report whose chart is 42, then:
client.delete(f"/api/v1/report/{blocking_report_id}")
client.delete('/api/v1/chart/', json={'ids': [42]})
Defensive patterns

Strategy: validation

Validate before calling

from superset.daos.report import ReportScheduleDAO
if ReportScheduleDAO.find_by_chart_ids(chart_ids):
    raise ValueError('chart is referenced by alerts/reports; remove them first')

Try / catch

from superset.commands.chart.exceptions import ChartDeleteFailedReportsExistError
try:
    DeleteChartCommand(ids).run()
except ChartDeleteFailedReportsExistError as ex:
    # ex.message lists the blocking report names
    detach_or_delete_reports(ex.message)

Prevention

When it happens

Trigger: DELETE /api/v1/chart/ for a chart attached to an Alert/Report schedule (delivered via email/Slack etc.); deleting a chart that sits on a dashboard targeted by a dashboard-report after the schedule was created against the chart itself.

Common situations: Cleaning up old charts without checking the Alerts & Reports page; inherited environments where legacy report schedules are invisible in the chart's UI.

Related errors


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