{"record":{"id":"4f1035fec47e162c","repo":"plandex-ai/plandex","slug":"error-validating-org-membership-4f1035","errorCode":null,"errorMessage":"Error validating org membership: ","messagePattern":"Error validating org membership: ","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"app/server/handlers/invites.go","lineNumber":102,"sourceCode":"\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\n\t\t}\n\n\t\tif isMember {\n\t\t\tlog.Println(\"User is already a member of org\")\n\t\t\thttp.Error(w, \"User is already a member of org\", http.StatusBadRequest)\n\t\t\treturn\n\t\t}\n\t}\n\n\t// ensure invite isn't already active\n\tinvite, err := db.GetActiveInviteByEmail(auth.OrgId, req.Email)\n\n\tif err != nil {\n\t\tlog.Printf(\"Error getting invite: %v\\n\", err)\n\t\thttp.Error(w, \"Error getting invite: \"+err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}","sourceCodeStart":84,"sourceCodeEnd":120,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/invites.go#L84-L120","documentation":"InviteUserHandler wraps any error returned by db.ValidateOrgMembership(user.Id, auth.OrgId) into an HTTP 500 prefixed with 'Error validating org membership: '. This is thrown when the database lookup that checks whether an existing user is already a member of the org fails for infrastructure reasons (connection loss, bad query, context cancellation), not because the user is or isn't a member. It indicates a server-side data-layer failure during invite creation.","triggerScenarios":"POST to the invite-user endpoint with an email that resolves to an existing user (db.GetUserByEmail returns non-nil) while the ValidateOrgMembership query fails: DB is down/restarting, connection pool exhausted, query timeout, request context canceled, or the org_membership/users table is missing or corrupted.","commonSituations":"Deployments where Postgres is under-provisioned or the connection pool is too small under load; transient network blips between the server and database; running migrations partially so org membership tables are missing; long-running requests canceled by client timeouts mid-handler.","solutions":["Check server logs for the same message to see the wrapped underlying DB error and fix that root cause first","Verify database connectivity (DATABASE_URL, network, Postgres uptime) and connection pool sizing","Confirm schema migrations have run so users/org membership tables exist with expected columns","Retry the invite request after the transient DB issue resolves","If it persists, add retry/backoff or better error wrapping around ValidateOrgMembership"],"exampleFix":"// before\nif err != nil {\n    http.Error(w, \"Error validating org membership: \"+err.Error(), http.StatusInternalServerError)\n    return\n}\n// after\nif err != nil {\n    log.Printf(\"Error validating org membership: %v\\n\", err)\n    writeApiError(w, shared.ApiError{Type: shared.ApiErrorTypeOther, Status: http.StatusInternalServerError, Msg: \"Failed to check org membership, please try again\"})\n    return\n}","handlingStrategy":"retry","validationCode":"// client: only call invite when you believe the email is new; nothing to pre-validate server-side,\n// but you can pre-check membership via the org members list before inviting\nif org.Members != nil {\n    for _, m := range org.Members {\n        if strings.ToLower(m.Email) == strings.ToLower(email) {\n            return fmt.Errorf(\"%s is already a member\", email)\n        }\n    }\n}","typeGuard":"func isMembershipValidationError(resp *http.Response, body string) bool {\n    return resp != nil && resp.StatusCode == http.StatusInternalServerError && strings.Contains(body, \"Error validating org membership\")\n}","tryCatchPattern":"resp, err := client.Post(inviteUrl, jsonBody)\nif err != nil { return err }\nbody, _ := io.ReadAll(resp.Body)\nif resp.StatusCode == 500 && strings.Contains(string(body), \"Error validating org membership\") {\n    return fmt.Errorf(\"transient server error checking membership; safe to retry: %s\", body)\n}","preventionTips":["Pre-check the org members list before sending an invite","Treat 500s on this endpoint as retryable after backoff","Monitor DB health/alerts so connectivity issues are caught early","Keep migrations in sync with deployed server code"],"tags":["database","http-500","invites","go"],"backgroundTag":"database-query-failed","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"}