{"record":{"id":"560f4e49c86546c2","repo":"plandex-ai/plandex","slug":"error-getting-org-member-role-id-v-560f4e","errorCode":null,"errorMessage":"error getting org member role id: %v","messagePattern":"error getting org member role id: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/db/rbac_helpers.go","lineNumber":30,"sourceCode":"\tif orgOwnerRoleId == \"\" {\n\t\terr := cacheOrgOwnerRoleId()\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"error getting org owner role id: %v\", err)\n\t\t}\n\t}\n\n\tif orgOwnerRoleId == \"\" {\n\t\treturn \"\", fmt.Errorf(\"org owner role id is empty\")\n\t}\n\n\treturn orgOwnerRoleId, nil\n}\n\nfunc GetOrgMemberRoleId() (string, error) {\n\tif orgMemberRoleId == \"\" {\n\t\terr := cacheOrgMemberRoleId()\n\t\tif err != nil {\n\t\t\treturn \"\", fmt.Errorf(\"error getting org member role id: %v\", err)\n\t\t}\n\t}\n\n\tif orgMemberRoleId == \"\" {\n\t\treturn \"\", fmt.Errorf(\"org member role id is empty\")\n\t}\n\n\treturn orgMemberRoleId, nil\n}\n\nfunc GetOrgOwners(orgId string) ([]*User, error) {\n\tvar users []*User\n\terr := Conn.Select(&users, \"SELECT * FROM users WHERE id IN (SELECT user_id FROM orgs_users WHERE org_id = $1 AND org_role_id = $2)\", orgId, orgOwnerRoleId)\n\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error getting org owners: %v\", err)\n\t}\n","sourceCodeStart":12,"sourceCodeEnd":48,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/db/rbac_helpers.go#L12-L48","documentation":"GetOrgMemberRoleId memoizes the 'member' org_roles id. If the cached global orgMemberRoleId is empty, it calls cacheOrgMemberRoleId; a failure of that DB lookup (missing row, dead connection, query error) is wrapped with this message. AddOrgDomainUsers therefore cannot resolve the role to assign to users.","triggerScenarios":"Calling AddOrgDomainUsers when the org_roles table lacks a 'member' row, the database is unreachable, or Conn is nil/not initialized.","commonSituations":"Database seeded with only some roles; migration partially applied; environment pointing at wrong database; DB restarted and connections dropped.","solutions":["Ensure seed data inserts the 'member' row into org_roles","Run CacheOrgRoleIds()/MustInitDb at startup so failures surface early","Verify connectivity: SELECT id FROM org_roles WHERE name = 'member';","Read the wrapped inner error to distinguish sql.ErrNoRows from connection failures"],"exampleFix":"// before\nmemberRoleId, err := GetOrgMemberRoleId()\nif err != nil { return err }\n// after\nif err := CacheOrgRoleIds(); err != nil {\n\treturn fmt.Errorf(\"role cache unavailable: %w\", err)\n}\nmemberRoleId, err := GetOrgMemberRoleId()","handlingStrategy":"try-catch","validationCode":"// before AddOrgDomainUsers\nvar n int\ndb.QueryRow(\"SELECT count(*) FROM org_roles WHERE name = 'member'\").Scan(&n)\nif n == 0 {\n\treturn fmt.Errorf(\"org_roles 'member' row missing; run seed migrations\")\n}","typeGuard":"func hasMemberRole(ctx context.Context, db *sql.DB) bool {\n\tvar n int\n\tif err := db.QueryRowContext(ctx, \"SELECT count(*) FROM org_roles WHERE name = 'member'\").Scan(&n); err != nil {\n\t\treturn false\n\t}\n\treturn n > 0\n}","tryCatchPattern":"memberRoleId, err := GetOrgMemberRoleId()\nif err != nil {\n\tif errors.Is(err, sql.ErrNoRows) || strings.Contains(err.Error(), \"no rows\") {\n\t\treturn fmt.Errorf(\"seed data missing: %w\", err)\n\t}\n\treturn fmt.Errorf(\"database unavailable: %w\", err)\n}","preventionTips":["Seed owner and member rows together in a single migration","Warm both caches at startup with CacheOrgRoleIds()","Add a readiness probe that verifies both role ids resolve"],"tags":["database","sql","rbac","cache"],"backgroundTag":"missing-db-seed-data","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"}