plandex-ai/plandex · warning
User is already a member of org
Error message
User is already a member of org
What it means
InviteUserHandler returns this 400 when db.ValidateOrgMembership reports that the user with the invited email already belongs to the target org. It is an expected, client-facing guard preventing duplicate invitations to existing members. The message means the invite is intentionally rejected, not that something failed.
Source
Thrown at app/server/handlers/invites.go:108
if err != nil {
log.Printf("Error getting user: %v\n", err)
http.Error(w, "Error getting user: "+err.Error(), http.StatusInternalServerError)
return
}
if user != nil {
isMember, err := db.ValidateOrgMembership(user.Id, auth.OrgId)
if err != nil {
log.Printf("Error validating org membership: %v\n", err)
http.Error(w, "Error validating org membership: "+err.Error(), http.StatusInternalServerError)
return
}
if isMember {
log.Println("User is already a member of org")
http.Error(w, "User is already a member of org", http.StatusBadRequest)
return
}
}
// ensure invite isn't already active
invite, err := db.GetActiveInviteByEmail(auth.OrgId, req.Email)
if err != nil {
log.Printf("Error getting invite: %v\n", err)
http.Error(w, "Error getting invite: "+err.Error(), http.StatusInternalServerError)
return
}
if invite != nil {
log.Println("Invite already exists")
http.Error(w, "Invite already exists", http.StatusBadRequest)
return
}View on GitHub (pinned to e2d772072e)
Solutions
- Treat the 400 as success from the admin's perspective: the user already has access
- Check the org's members list before sending invites to dedupe
- If the user should not be a member, remove them from the org first, then invite
- Surface a friendlier client message like 'This person is already in your org'
Example fix
// before
if isMember {
http.Error(w, "User is already a member of org", http.StatusBadRequest)
return
}
// after
if isMember {
writeApiError(w, shared.ApiError{Type: shared.ApiErrorTypeOther, Status: http.StatusConflict, Msg: "User is already a member of this org"})
return
} Defensive patterns
Strategy: validation
Validate before calling
// client: check the org's member emails before inviting
memberEmails := map[string]bool{}
for _, m := range org.Members {
memberEmails[strings.ToLower(m.Email)] = true
}
if memberEmails[strings.ToLower(email)] {
return fmt.Errorf("%s is already a member of the org", email)
} Type guard
func isAlreadyMemberError(statusCode int, body string) bool {
return statusCode == http.StatusBadRequest && strings.Contains(body, "User is already a member of org")
} Try / catch
resp, err := client.Post(inviteUrl, jsonBody)
body, _ := io.ReadAll(resp.Body)
if resp.StatusCode == 400 && strings.Contains(string(body), "already a member") {
// not a failure: user already has access
return nil
} Prevention
- Deduplicate against the members list in the invite UI before submitting
- Remember auto-add-domain orgs grant access implicitly by email domain
- Normalize emails to lowercase before comparing
- Show 'already in org' as a benign notice, not an error
When it happens
Trigger: POST to the invite-user endpoint whose req.Email matches an existing user account that is already an org member of auth.OrgId (e.g. the user signed up and joined via auto-add domain or accepted an earlier invite).
Common situations: Admins re-inviting a coworker who already joined; auto-add-domain orgs where the user already gained access through their email domain; retrying an invite after the invitee already accepted in another tab; case differences that bypass the client's dedupe check (server lowercases email but the admin typed a variant).
Related errors
- Invite already exists
- Error parsing request body
- Cannot delete main branch
- User already has access to org via domain:
- Error parsing request body
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/c74f5e59894429f1.
Report an issue: GitHub.