{"record":{"id":"b4dd944c358fe04a","repo":"apache/superset","slug":"changing-this-dataset-is-forbidden-b4dd94","errorCode":null,"errorMessage":"Changing this dataset is forbidden.","messagePattern":"Changing this dataset is forbidden\\.","errorType":"exception","errorClass":"DatasetMetricForbiddenError","httpStatus":500,"severity":"error","filePath":"superset/commands/dataset/metrics/delete.py","lineNumber":57,"sourceCode":"        self._model_id = model_id\n        self._model: Optional[SqlMetric] = None\n\n    @transaction(on_error=partial(on_error, reraise=DatasetMetricDeleteFailedError))\n    def run(self) -> None:\n        self.validate()\n        assert self._model\n        DatasetMetricDAO.delete([self._model])\n\n    def validate(self) -> None:\n        # Validate/populate model exists\n        self._model = DatasetDAO.find_dataset_metric(self._dataset_id, self._model_id)\n        if not self._model:\n            raise DatasetMetricNotFoundError()\n        # Check editorship\n        try:\n            security_manager.raise_for_editorship(self._model)\n        except SupersetSecurityException as ex:\n            raise DatasetMetricForbiddenError() from ex\n","sourceCodeStart":39,"sourceCodeEnd":58,"githubUrl":"https://github.com/apache/superset/blob/f4587218dd19d046c3e4d00063e7d27f8a2ed354/superset/commands/dataset/metrics/delete.py#L39-L58","documentation":"DatasetMetricForbiddenError is raised by DeleteDatasetMetricCommand.validate() when security_manager.raise_for_editorship(self._model) denies the current user the right to edit the dataset metric. Editorship means the user is an owner of the metric's parent dataset or holds a role with the change-dataset capability. The original SupersetSecurityException is chained as the cause for auditability.","triggerScenarios":"Calling DELETE /api/v1/dataset/{dataset_id}/metric/{metric_id} (which routes to DeleteDatasetMetricCommand) while the authenticated user is neither an owner of the dataset nor an Admin/role with dataset-edit rights. Also triggered when the metric resolves to a dataset the user can read but not edit.","commonSituations":"A Gamma/Analyst user with only 'can show dataset' / read access tries to prune computed metrics via the API or a script. Service accounts whose token belongs to a viewer role. Ownership changed (dataset re-owned to another team) and stale automation keeps calling the delete endpoint.","solutions":["Have an owner of the dataset perform the delete, or add the current user to the dataset's owners (PUT /api/v1/dataset/{id} with owners).","Grant the calling role the dataset-edit permission (e.g. can_edit on Dataset model, or Admin role) in List Roles.","Verify you are hitting the right dataset_id/metric_id pair — the 403 here comes after a successful lookup, so the IDs are valid but rights are missing.","If using a service token, re-issue it for a user with the required role."],"exampleFix":"# before\ncurl -X DELETE -H \"Authorization: Bearer $VIEWER_TOKEN\" \\\n  https://superset/api/v1/dataset/42/metric/7\n# -> 403 Changing this dataset is forbidden.\n\n# after: perform as an owner/admin\ncurl -X DELETE -H \"Authorization: Bearer $ADMIN_TOKEN\" \\\n  https://superset/api/v1/dataset/42/metric/7","handlingStrategy":"validation","validationCode":"from superset import security_manager\nfrom superset.daos.dataset import DatasetDAO\n\nmodel = DatasetDAO.find_dataset_metric(dataset_id, metric_id)\nif model is None:\n    ...  # 404 path\nif not security_manager.can_access(\"can_write\", \"Dataset\") and user_id not in (\n    o.id for o in model.table.owners\n):\n    abort(403, \"not an editor of this dataset\")","typeGuard":null,"tryCatchPattern":"try:\n    DeleteDatasetMetricCommand(dataset_id, metric_id).run()\nexcept DatasetMetricForbiddenError:\n    # surface 'ask an owner' message; do not retry with same credentials\n    respond_403_with_owner_hint()","preventionTips":["Check dataset ownership before scripting metric deletions.","Give automation accounts a role with dataset write permissions.","Treat 403 as terminal for the credential, never retry-loop it."],"tags":["permissions","rbac","dataset","metric","api"],"backgroundTag":null,"analyzedSha":"f4587218dd19d046c3e4d00063e7d27f8a2ed354","analyzedAt":"2026-08-14T22:39:27.425Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}