{"record":{"id":"e6bb70c26da3de91","repo":"plandex-ai/plandex","slug":"user-does-not-have-permission-to-remove-user-with","errorCode":null,"errorMessage":"User does not have permission to remove user with role: {orgUser.OrgRoleId}","messagePattern":"User does not have permission to remove user with role: (.+?)","errorType":"http","errorClass":null,"httpStatus":403,"severity":"warning","filePath":"app/server/handlers/users.go","lineNumber":144,"sourceCode":"\tvars := mux.Vars(r)\n\tuserId := vars[\"userId\"]\n\n\tlog.Println(\"userId: \", userId)\n\n\torgUser, err := db.GetOrgUser(userId, auth.OrgId)\n\n\tif err != nil {\n\t\tlog.Printf(\"Error getting org user: %v\\n\", err)\n\t\thttp.Error(w, \"Error getting org user: \"+err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\t// ensure current user can remove target user\n\tremovePermission := shared.Permission(strings.Join([]string{string(shared.PermissionRemoveUser), orgUser.OrgRoleId}, \"|\"))\n\n\tif !auth.HasPermission(removePermission) {\n\t\tlog.Printf(\"User does not have permission to remove user with role: %v\\n\", orgUser.OrgRoleId)\n\t\thttp.Error(w, \"User does not have permission to remove user with role: \"+orgUser.OrgRoleId, http.StatusForbidden)\n\t\treturn\n\t}\n\n\t// verify user is org member\n\tisMember, err := db.ValidateOrgMembership(userId, auth.OrgId)\n\n\tif err != nil {\n\t\tlog.Printf(\"Error validating org membership: %v\\n\", err)\n\t\thttp.Error(w, \"Error validating org membership: \"+err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tif !isMember {\n\t\tlog.Printf(\"User %s is not a member of org %s\\n\", userId, auth.OrgId)\n\t\thttp.Error(w, \"User \"+userId+\" is not a member of org \"+auth.OrgId, http.StatusForbidden)\n\t\treturn\n\t}\n","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/users.go#L126-L162","documentation":"The authenticated caller lacks the composite permission \"remove-user|<targetOrgRoleId>\", so DeleteOrgUserHandler refuses with HTTP 403. The permission is dynamically built by joining PermissionRemoveUser with the target user's OrgRoleId, meaning callers need a matching grant per target role (e.g. separate grants for removing members vs admins vs owners).","triggerScenarios":"Caller's role permission set does not include remove-user|<role> for the specific OrgRoleId of the target user — e.g. an admin tries to delete another admin or an owner, or a member tries to delete anyone.","commonSituations":"Role config updated but the caller's cached JWT still has old permissions; only owner-level removal was granted but target is an admin; reusing an integration token with a read-only role; per-role permission scheme misunderstood by API consumers.","solutions":["Grant the caller's role the permission string remove-user|<orgUser.OrgRoleId> (exact pipe-joined form) in role config","Check which role the target user has (org_users.org_role_id) and confirm your permission covers that specific role","Re-authenticate to refresh permissions if role grants were changed recently","Use a role with sufficient privileges (e.g. org owner) to perform the removal"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"required := \"remove-user|\" + targetOrgRoleId\nhasIt := slices.Contains(callerPermissions, required)\nif !hasIt {\n    return fmt.Errorf(\"missing permission %s\", required)\n}","typeGuard":"func canRemoveUser(perms []shared.Permission, targetRoleId string) bool {\n    p := shared.Permission(\"remove-user|\" + targetRoleId)\n    return slices.Contains(perms, p)\n}","tryCatchPattern":"if !auth.HasPermission(removePermission) {\n    http.Error(w, \"forbidden: missing \"+string(removePermission), http.StatusForbidden)\n    return\n}\n// client side:\n// if resp.StatusCode == http.StatusForbidden { stop; surface 'insufficient permissions' }","preventionTips":["Grant per-role removal permissions in the exact pipe-joined format remove-user|<role>","Re-issue tokens after changing role grants so permissions are fresh","Document which roles may remove which target roles for API consumers","Pre-check permissions client-side and disable delete actions that would 403"],"tags":["go","authorization","permissions","http-403","rbac"],"backgroundTag":"insufficient-permissions","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}