{"record":{"id":"47e56ee2d71b55d0","repo":"plandex-ai/plandex","slug":"user-userid-is-not-a-member-of-org-auth-orgid","errorCode":null,"errorMessage":"User {userId} is not a member of org {auth.OrgId}","messagePattern":"User (.+?) is not a member of org (.+?)","errorType":"http","errorClass":null,"httpStatus":403,"severity":"warning","filePath":"app/server/handlers/users.go","lineNumber":159,"sourceCode":"\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\n\torgOwnerRoleId, err := db.GetOrgOwnerRoleId()\n\n\tif err != nil {\n\t\tlog.Printf(\"Error getting org owner role id: %v\\n\", err)\n\t\thttp.Error(w, \"Error getting org owner role id: \"+err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\t// verify user isn't the only org owner\n\tif orgUser.OrgRoleId == orgOwnerRoleId {\n\t\tnumOwners, err := db.NumUsersWithRole(auth.OrgId, orgOwnerRoleId)\n\n\t\tif err != nil {\n\t\t\tlog.Printf(\"Error getting number of org owners: %v\\n\", err)\n\t\t\thttp.Error(w, \"Error getting number of org owners: \"+err.Error(), http.StatusInternalServerError)","sourceCodeStart":141,"sourceCodeEnd":177,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/users.go#L141-L177","documentation":"The membership check succeeded but returned false: the target userId is not a member of the authenticated org. The handler responds 403 'User <userId> is not a member of org <orgId>'. This is a caller-input problem — the userId path parameter points at someone outside (or removed from) this org.","triggerScenarios":"DELETE /users/<userId> where userId exists in the system but has no membership in auth.OrgId — wrong org id in token, stale client list, or the target already left/was removed.","commonSituations":"Client iterating a cached user list after the member was removed elsewhere; multi-org user whose membership in this org lapsed; calling the endpoint against the wrong org context; case-mismatched org id.","solutions":["Verify the target user is still a member of the org (SELECT * FROM org_users WHERE user_id = ... AND org_id = ...)","Refresh the client's user list before deleting; treat 403 as 'not a member' and skip","Ensure the caller's auth token belongs to the intended org","If the user should be a member, re-add them via invite before deleting"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"var member bool\nerr := db.Get(&member,\n  \"SELECT EXISTS(SELECT 1 FROM org_users WHERE user_id=$1 AND org_id=$2)\",\n  targetUserId, myOrgId)\nif err == nil && !member {\n    return errors.New(\"target is not a member of this org\")\n}","typeGuard":"func isOrgMember(db *sqlx.DB, userId, orgId string) bool {\n    var ok bool\n    _ = db.Get(&ok, \"SELECT EXISTS(SELECT 1 FROM org_users WHERE user_id=$1 AND org_id=$2)\", userId, orgId)\n    return ok\n}","tryCatchPattern":"if !isMember {\n    http.Error(w, \"User \"+userId+\" is not a member of org \"+auth.OrgId, http.StatusForbidden)\n    return\n}\n// client side:\n// if resp.StatusCode == 403 && strings.HasPrefix(msg, \"User \") { skip; refresh list }","preventionTips":["Refresh the org member list before issuing deletes; skip users no longer present","Confirm the auth token's org matches the org the client is operating on","Handle self-removal and already-removed members idempotently in scripts","Check membership with a direct query when unsure before calling the API"],"tags":["go","authorization","membership","http-403","user-management"],"backgroundTag":"not-a-member-of-org","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}