apache/superset · error · ReportScheduleForbiddenError

Changing this report is forbidden

Error message

Changing this report is forbidden

What it means

ReportScheduleForbiddenError from DeleteReportCommand.validate: for each loaded model the command calls security_manager.raise_for_editorship(model), and a raised SupersetSecurityException is wrapped as 'Changing this report is forbidden'. Only owners (or admins) may delete a report schedule.

Source

Thrown at superset/commands/report/delete.py:58

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

    def validate(self) -> None:
        # Validate/populate model exists
        self._models = ReportScheduleDAO.find_by_ids(self._model_ids)
        if not self._models or len(self._models) != len(self._model_ids):
            raise ReportScheduleNotFoundError()

        # Check editorship
        for model in self._models:
            try:
                security_manager.raise_for_editorship(model)
            except SupersetSecurityException as ex:
                raise ReportScheduleForbiddenError() from ex

View on GitHub (pinned to f4587218dd)

Solutions

  1. Have an admin (or the current owner) perform the delete, or add the caller to the report's owners first
  2. For service-account automation, create reports with that account as owner from the start
  3. Batch deletes should be pre-filtered to rows the caller owns

Example fix

# before
DeleteReportCommand(current_user, [report_id]).run()  # not an owner -> 403

# after
# admin adds the caller as owner, then:
UpdateReportCommand(admin, report_id, {'owners': [*old_owners, current_user.id]}).run()
DeleteReportCommand(current_user, [report_id]).run()
Defensive patterns

Strategy: validation

Validate before calling

from superset import security_manager

for rid in report_ids:
    model = ReportScheduleDAO.find_by_id(rid)
    if model and not security_manager.is_owner(model):
        raise PermissionError(f'not an owner of report {rid}')  # fail before the command

Try / catch

try:
    DeleteReportCommand(user, ids).run()
except ReportScheduleForbiddenError:
    # route to an admin, or add caller to owners first
    ...

Prevention

When it happens

Trigger: DELETE /api/v1/report/{id} by a user who is not in the report's owners list and lacks admin rights. Mixed batches where the caller owns some but not all targeted reports also fail on the first non-owned model.

Common situations: A teammate left and their reports are orphaned; scripts run as a service account that never owned the schedules; role has can_delete on ReportSchedule but the object-level owner check still denies.

Understand the failure class

Related errors


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