{"record":{"id":"30e77233e4388ff1","repo":"apache/superset","slug":"changing-this-dashboard-is-forbidden","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/copy.py","lineNumber":64,"sourceCode":"        # dashboard's baseline records read as \"Cloned from <source>\"\n        # in the timeline instead of \"Dashboard created\".\n        # Method-scoped imports — defer the versioning bootstrap path\n        # (``Model.metadata`` and Continuum-adjacent setup) out of this\n        # command's module-load graph; see ``changes.py`` module\n        # docstring for the broader init-order rationale.\n        from superset import db\n        from superset.versioning.changes import ACTION_KIND_CLONE, ACTION_KIND_KEY\n\n        db.session.info[ACTION_KIND_KEY] = ACTION_KIND_CLONE\n        return DashboardDAO.copy_dashboard(self._original_dash, self._properties)\n\n    def validate(self) -> None:\n        if not self._properties.get(\"dashboard_title\") or not self._properties.get(\n            \"json_metadata\"\n        ):\n            raise DashboardInvalidError()\n        if not security_manager.is_editor(self._original_dash):\n            raise DashboardForbiddenError()\n","sourceCodeStart":46,"sourceCodeEnd":65,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset/commands/dashboard/copy.py#L46-L65","documentation":"DashboardForbiddenError is raised by CopyDashboardCommand.validate() when security_manager.is_editor(original_dashboard) returns False. Superset requires editor-level rights on the source dashboard (owner, admin, or a role with the appropriate can_edit capability) before allowing a copy, because the copy exposes the full dashboard definition.","triggerScenarios":"Calling the dashboard copy API as a user who can view but not edit the source dashboard: not an owner, not an admin, and role lacks the dashboard edit permission.","commonSituations":"Viewer/Gamma-style roles attempting to duplicate shared dashboards; users assuming 'can view' implies 'can copy'; org policies where dashboards are owned by a service account and nobody else can copy them.","solutions":["Ask an owner or admin to add the calling user as an owner (or editor) of the source dashboard, then retry the copy.","Use an admin account for bulk copy automation.","If the policy should allow viewers to copy, grant the role the dashboard edit permission via Roles -> Permissions, understanding this widens edit rights too."],"exampleFix":"# before\nCopyDashboardCommand(dash, props).run()  # user is viewer only\n\n# after\nfrom superset.extensions import security_manager\nif security_manager.is_editor(dash):\n    CopyDashboardCommand(dash, props).run()\nelse:\n    raise PermissionError(\"Request ownership of the dashboard before copying\")","handlingStrategy":"try-catch","validationCode":"from superset.extensions import security_manager\n\nif not security_manager.is_editor(src_dashboard):\n    raise PermissionError('must be an editor/owner of the dashboard to copy it')","typeGuard":null,"tryCatchPattern":"try:\n    CopyDashboardCommand(src, props).run()\nexcept DashboardForbiddenError:\n    prompt_user_for_ownership_or_use_admin()","preventionTips":["Check is_editor before offering a 'duplicate' button in the UI.","Run copy automation as an account with ownership of source dashboards.","Remember view access never implies copy access in Superset."],"tags":["security","rbac","dashboard","copy","forbidden"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}