{"record":{"id":"6c77fa5617fa6d76","repo":"plandex-ai/plandex","slug":"user-already-has-access-to-org-via-domain","errorCode":null,"errorMessage":"User already has access to org via domain: ","messagePattern":"User already has access to org via domain: ","errorType":"http","errorClass":null,"httpStatus":400,"severity":"info","filePath":"app/server/handlers/invites.go","lineNumber":85,"sourceCode":"\n\tif !auth.HasPermission(permission) {\n\t\tlog.Printf(\"User does not have permission to invite user with role: %v\\n\", req.OrgRoleId)\n\t\thttp.Error(w, \"User does not have permission to invite user with role: \"+req.OrgRoleId, http.StatusForbidden)\n\t\treturn\n\t}\n\n\t// ensure user doesn't already have access to org via domain\n\tsplit := strings.Split(req.Email, \"@\")\n\tif len(split) != 2 {\n\t\tlog.Printf(\"Invalid email: %v\\n\", req.Email)\n\t\thttp.Error(w, \"Invalid email: \"+req.Email, http.StatusBadRequest)\n\t\treturn\n\t}\n\tdomain := &split[1]\n\n\tif org.AutoAddDomainUsers && org.Domain == domain {\n\t\tlog.Printf(\"User already has access to org via domain: %v\\n\", domain)\n\t\thttp.Error(w, \"User already has access to org via domain: \"+*domain, http.StatusBadRequest)\n\t}\n\n\t// ensure user with this email isn't already in the org\n\tuser, err := db.GetUserByEmail(req.Email)\n\n\tif err != nil {\n\t\tlog.Printf(\"Error getting user: %v\\n\", err)\n\t\thttp.Error(w, \"Error getting user: \"+err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tif user != nil {\n\t\tisMember, err := db.ValidateOrgMembership(user.Id, auth.OrgId)\n\n\t\tif err != nil {\n\t\t\tlog.Printf(\"Error validating org membership: %v\\n\", err)\n\t\t\thttp.Error(w, \"Error validating org membership: \"+err.Error(), http.StatusInternalServerError)\n\t\t\treturn","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/invites.go#L67-L103","documentation":"If the org has AutoAddDomainUsers enabled and the invitee's email domain equals the org's Domain, the handler responds 400 with 'User already has access to org via domain: <domain>'. Such users join automatically, so an explicit invite is redundant and rejected. Note the code writes the error but does not return, so execution continues to GetUserByEmail afterward.","triggerScenarios":"Inviting an email whose domain (after '@') matches the org's configured Domain while AutoAddDomainUsers is true — e.g. org domain 'acme.com' with auto-add on, inviting 'newhire@acme.com'.","commonSituations":"Admins manually inviting colleagues from their company domain, not realizing auto-add already covers them; the org's Domain setting changed to a broad value so many invites now collide; invited person already signed up via the domain flow.","solutions":["Don't send the invite — instruct the user to sign up/log in with their company email; they'll be added to the org automatically via the domain rule","If an invite is genuinely needed, disable AutoAddDomainUsers in org settings or ask an admin to change the org Domain","As a client, check org.AutoAddDomainUsers and org.Domain before calling the invite API and skip/short-circuit matching emails","On the server, consider adding a 'return' after this http.Error to stop processing (currently execution continues, which can cause a second write)"],"exampleFix":"// before\nif org.AutoAddDomainUsers && org.Domain == domain {\n    log.Printf(\"User already has access to org via domain: %v\\n\", domain)\n    http.Error(w, \"User already has access to org via domain: \"+*domain, http.StatusBadRequest)\n}\n// after\nif org.AutoAddDomainUsers && org.Domain == domain {\n    log.Printf(\"User already has access to org via domain: %v\\n\", domain)\n    http.Error(w, \"User already has access to org via domain: \"+*domain, http.StatusBadRequest)\n    return\n}","handlingStrategy":"validation","validationCode":"// Skip the invite if the org auto-adds this email's domain\norg, err := client.GetOrg(ctx)\nif err != nil {\n    return err\n}\ndomain := email[strings.LastIndex(email, \"@\")+1:]\nif org.AutoAddDomainUsers && strings.EqualFold(org.Domain, domain) {\n    return fmt.Errorf(\"%s already has access via domain %s — no invite needed\", email, domain)\n}","typeGuard":"func coveredByAutoAdd(org *Org, email string) bool {\n    if org == nil || !org.AutoAddDomainUsers || org.Domain == \"\" {\n        return false\n    }\n    parts := strings.Split(email, \"@\")\n    return len(parts) == 2 && strings.EqualFold(parts[1], org.Domain)\n}","tryCatchPattern":"err := client.InviteUser(ctx, email, roleID)\nif err != nil && strings.Contains(err.Error(), \"already has access to org via domain\") {\n    // Not a failure: tell the user to sign up with their company email instead\n    return ErrAutoDomainCovered\n}","preventionTips":["Check org.AutoAddDomainUsers and org.Domain before inviting same-domain emails","Treat this 400 as informational — direct the user through the domain join flow","Watch for org Domain setting changes that suddenly broaden auto-add coverage","Server-side: add a return after this http.Error so the handler stops processing"],"tags":["validation","org-settings","http","invites"],"backgroundTag":"domain-auto-add-conflict","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"}