{"record":{"id":"ae890ca1cbc24e2e","repo":"apolloconfig/apollo","slug":"forbidden-operation-caused-by-1-you-don-t-have-r-ae890c","errorCode":null,"errorMessage":"Forbidden operation. Caused by: 1.you don't have release permission or 2. you don't have modification permission or 3. you have modification permission but branch has been released","messagePattern":"Forbidden operation\\. Caused by: 1\\.you don't have release permission or 2\\. you don't have modification permission or 3\\. you have modification permission but branch has been released","errorType":"http","errorClass":"AccessDeniedException","httpStatus":403,"severity":"warning","filePath":"apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/NamespaceBranchController.java","lineNumber":116,"sourceCode":"  }\n\n  @DeleteMapping(\n      value = \"/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}\")\n  @ApolloAuditLog(type = OpType.DELETE, name = \"NamespaceBranch.delete\")\n  public void deleteBranch(@PathVariable String appId, @PathVariable String env,\n      @PathVariable String clusterName, @PathVariable String namespaceName,\n      @PathVariable String branchName) {\n\n    boolean hasModifyPermission = unifiedPermissionValidator.hasModifyNamespacePermission(appId,\n        env, clusterName, namespaceName);\n    boolean hasReleasePermission = unifiedPermissionValidator.hasReleaseNamespacePermission(appId,\n        env, clusterName, namespaceName);\n    boolean canDelete = hasReleasePermission || (hasModifyPermission && releaseService\n        .loadLatestRelease(appId, Env.valueOf(env), branchName, namespaceName) == null);\n\n\n    if (!canDelete) {\n      throw new AccessDeniedException(\n          \"Forbidden operation. \" + \"Caused by: 1.you don't have release permission \"\n              + \"or 2. you don't have modification permission \"\n              + \"or 3. you have modification permission but branch has been released\");\n    }\n\n    namespaceBranchService.deleteBranch(appId, Env.valueOf(env), clusterName, namespaceName,\n        branchName, userInfoHolder.getUser().getUserId());\n\n  }\n\n\n\n  @PreAuthorize(\n      value = \"@unifiedPermissionValidator.hasModifyNamespacePermission(#appId, #env, #clusterName, #namespaceName)\")\n  @PostMapping(\n      value = \"/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName}/merge\")\n  @ApolloAuditLog(type = OpType.UPDATE, name = \"NamespaceBranch.merge\")\n  public ReleaseDTO merge(@PathVariable String appId, @PathVariable String env,","sourceCodeStart":98,"sourceCodeEnd":134,"githubUrl":"https://github.com/apolloconfig/apollo/blob/d95fc18d112589efc09ddcbe1507047584d55251/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/NamespaceBranchController.java#L98-L134","documentation":"AccessDeniedException (HTTP 403) from NamespaceBranchController delete-branch. Deletion is allowed only when canDelete is true: the user has ReleaseNamespace permission, OR (has ModifyNamespace permission AND the branch has never been released, i.e. loadLatestRelease returns null). If none of those hold the operation is forbidden with this enumerated-cause message.","triggerScenarios":"DELETE /apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/branches/{branchName} by a user who neither has release permission nor the (modify + unreleased-branch) combination.","commonSituations":"A modify-only user trying to delete a branch that already has a published release; a user with no namespace role at all; deleting a gray branch after it was merged/released.","solutions":["Ask a user with ReleaseNamespace permission to delete the branch.","If you only have modify rights, delete the branch before it has been released (loadLatestRelease must be null).","Verify your role assignment on the app/env/cluster/namespace via the portal.","Confirm the branch hasn't already been released (cause #3)."],"exampleFix":"// No code fix: this is an authorization gate.\n// Resolution: act as a user holding ReleaseNamespace permission, or delete before first release.","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Branch delete can 403 with the enumerated-cause message.\ntry {\n  portal.deleteBranch(appId, env, cluster, namespace, branch);\n} catch (HttpClientErrorException.Forbidden e) {\n  // Inspect causes: lacks release permission, lacks modify permission, or branch already released.\n  if (branchHasBeenReleased) {\n    report(\"cannot delete: branch already released; ask a release-permission user\");\n  } else {\n    report(\"insufficient permission to delete branch\");\n  }\n}","preventionTips":["Delete gray branches before they are released if you only hold modify rights.","Have a ReleaseNamespace-permissioned user perform branch deletion.","Check loadLatestRelease state before attempting delete.","Surface the three enumerated causes to the end user."],"tags":["permission","access-denied","branch","release","role"],"backgroundTag":null,"analyzedSha":"d95fc18d112589efc09ddcbe1507047584d55251","analyzedAt":"2026-08-14T04:00:05.477Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}