{"record":{"id":"ff43aaa6005566c9","repo":"plandex-ai/plandex","slug":"error-getting-number-of-org-owners-err-error","errorCode":null,"errorMessage":"Error getting number of org owners: {err.Error()}","messagePattern":"Error getting number of org owners: (.+?)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"app/server/handlers/users.go","lineNumber":177,"sourceCode":"\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)\n\t\t\treturn\n\t\t}\n\n\t\tif numOwners == 1 {\n\t\t\tlog.Println(\"Cannot delete the only org owner\")\n\t\t\thttp.Error(w, \"Cannot delete the only org owner\", http.StatusForbidden)\n\t\t\treturn\n\t\t}\n\t}\n\n\terr = db.WithTx(r.Context(), \"delete org user\", func(tx *sqlx.Tx) error {\n\n\t\terr = db.DeleteOrgUser(auth.OrgId, userId, tx)\n\n\t\tif err != nil {\n\t\t\tlog.Println(\"Error deleting org user: \", err)\n\t\t\treturn fmt.Errorf(\"error deleting org user: %v\", err)\n\t\t}","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/users.go#L159-L195","documentation":"When the target user is an org owner, the handler counts owners via db.NumUsersWithRole(auth.OrgId, orgOwnerRoleId); that count query returned an error, so the last-owner safety check cannot complete and the request fails with HTTP 500.","triggerScenarios":"NumUsersWithRole fails during a DELETE of an owner-role user — DB connection failure, timeout, or schema problem in the count query.","commonSituations":"DB under heavy load causing count-query timeouts; connection pool exhausted by concurrent requests; migration altered the column the count query filters on.","solutions":["Check server logs for the wrapped NumUsersWithRole error (timeout vs connection vs syntax)","Verify DB health and connection pool settings; retry after transient failures","Confirm the org_users schema columns used by the count query still match migrations","If recurring under load, index org_users(org_id, org_role_id) to speed the count"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"var n int\nerr := db.Get(&n,\n  \"SELECT COUNT(*) FROM org_users WHERE org_id=$1 AND org_role_id=$2\",\n  orgId, ownerRoleId)\nif err == nil {\n    fmt.Printf(\"org has %d owners\\n\", n)\n}","typeGuard":null,"tryCatchPattern":"numOwners, err := db.NumUsersWithRole(auth.OrgId, orgOwnerRoleId)\nif err != nil {\n    if isTransientDBError(err) {\n        // retry with backoff before failing the request\n    }\n    http.Error(w, \"internal error\", http.StatusInternalServerError)\n    return\n}","preventionTips":["Add an index on org_users(org_id, org_role_id) so owner counts stay fast","Set statement timeouts and pool limits that tolerate count queries under load","Retry transient DB failures with exponential backoff before surfacing 500","Watch DB latency metrics and scale the instance before timeouts appear"],"tags":["go","database","timeout","http-500","owners-check"],"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"}