{"record":{"id":"ad762e2096943a67","repo":"apache/superset","slug":"changing-this-dashboard-is-forbidden-ad762e","errorCode":null,"errorMessage":"Changing this Dashboard is forbidden","messagePattern":"Changing this Dashboard is forbidden","errorType":"exception","errorClass":"DashboardForbiddenError","httpStatus":403,"severity":"error","filePath":"superset/commands/dashboard/delete.py","lineNumber":54,"sourceCode":"from superset.utils.decorators import on_error, transaction\n\nlogger = logging.getLogger(__name__)\n\n\nclass DeleteEmbeddedDashboardCommand(BaseCommand):\n    def __init__(self, dashboard: Dashboard):\n        self._dashboard = dashboard\n\n    @transaction(on_error=partial(on_error, reraise=DashboardDeleteEmbeddedFailedError))\n    def run(self) -> None:\n        self.validate()\n        return EmbeddedDashboardDAO.delete(self._dashboard.embedded)\n\n    def validate(self) -> None:\n        try:\n            security_manager.raise_for_editorship(self._dashboard)\n        except SupersetSecurityException as ex:\n            raise DashboardForbiddenError() from ex\n\n\nclass DeleteDashboardCommand(BaseCommand):\n    def __init__(self, model_ids: list[int]):\n        self._model_ids = model_ids\n        self._models: Optional[list[Dashboard]] = None\n\n    @transaction(on_error=partial(on_error, reraise=DashboardDeleteFailedError))\n    def run(self) -> None:\n        self.validate()\n        assert self._models\n        DashboardDAO.delete(self._models)\n\n    def validate(self) -> None:\n        # Validate/populate model exists\n        self._models = DashboardDAO.find_by_ids(self._model_ids)\n        if not self._models or len(self._models) != len(self._model_ids):\n            raise DashboardNotFoundError()","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset/commands/dashboard/delete.py#L36-L72","documentation":"DashboardForbiddenError is raised by DeleteEmbeddedDashboardCommand.validate() when security_manager.raise_for_editorship(dashboard) throws SupersetSecurityException. Deleting a dashboard's embedded configuration counts as modifying the dashboard, so only owners/editors/admins may do it.","triggerScenarios":"Calling the embedded-delete flow (DELETE on the dashboard's embedded resource, e.g. /api/v1/dashboard/<id>/embedded) as a user who cannot edit the dashboard. Also triggered by code paths that clear embedded config during dashboard updates when the actor is a viewer.","commonSituations":"Non-owner admins of restricted deployments trying to disable embedded mode; automated cleanup scripts running under a low-privilege service account; embedded-guest flows that mistakenly invoke deletion.","solutions":["Perform the embedded deletion as a dashboard owner or admin user.","For service accounts, grant a role with dashboard edit/editor permission on that dashboard.","Check the actor in background jobs: embedded deletion in async code inherits the job's user context, which may be None or a limited user."],"exampleFix":"# before\nDeleteEmbeddedDashboardCommand(dash).run()  # viewer user -> 403\n\n# after\nfrom superset.extensions import security_manager\ntry:\n    DeleteEmbeddedDashboardCommand(dash).run()\nexcept DashboardForbiddenError:\n    # re-run as owner or surface a permission prompt\n    raise","handlingStrategy":"try-catch","validationCode":"from superset.extensions import security_manager\n\ntry:\n    security_manager.raise_for_editorship(dashboard)\nexcept SupersetSecurityException:\n    raise PermissionError('editorship required to delete embedded config')","typeGuard":null,"tryCatchPattern":"try:\n    DeleteEmbeddedDashboardCommand(dashboard).run()\nexcept DashboardForbiddenError:\n    # retry as owner/admin or surface permission error to user\n    escalate_permission_error(dashboard.id)","preventionTips":["Only expose embedded-config controls to editors in the UI.","Keep background jobs' user context explicit when they touch embedded settings.","Service accounts used for cleanup need editorship or admin."],"tags":["security","rbac","dashboard","embedded","delete"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}