{"record":{"id":"ea4a401cfbb37c23","repo":"plandex-ai/plandex","slug":"org-member-role-id-is-empty","errorCode":null,"errorMessage":"org member role id is empty","messagePattern":"org member role id is empty","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/server/db/rbac_helpers.go","lineNumber":35,"sourceCode":"\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\n\treturn users, nil\n}\n\nfunc CacheOrgRoleIds() error {\n\terr := cacheOrgOwnerRoleId()","sourceCodeStart":17,"sourceCodeEnd":53,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/db/rbac_helpers.go#L17-L53","documentation":"Fallback guard in GetOrgMemberRoleId: the member-role DB lookup reported success but the cached orgMemberRoleId is still empty, so the function returns this error instead of an invalid role id. Like error 481, it signals inconsistent cache state.","triggerScenarios":"cacheOrgMemberRoleId returned nil but did not populate the global (corrupted caching logic), or the global was cleared concurrently after caching.","commonSituations":"Concurrent initialization races; manual edits to package globals; schema where the 'member' row id is an empty string.","solutions":["Initialize via CacheOrgRoleIds() during startup and abort on failure","Protect cache population with sync.Once or a mutex","Retry the lookup once inside this branch before returning the error","Audit for code that resets orgMemberRoleId at runtime"],"exampleFix":"// before\nif orgMemberRoleId == \"\" {\n\treturn \"\", fmt.Errorf(\"org member role id is empty\")\n}\n// after\nif orgMemberRoleId == \"\" {\n\tif err := cacheOrgMemberRoleId(); err != nil {\n\t\treturn \"\", fmt.Errorf(\"org member role id is empty: %v\", err)\n\t}\n}","handlingStrategy":"validation","validationCode":"if orgMemberRoleId == \"\" {\n\tif err := CacheOrgRoleIds(); err != nil {\n\t\treturn fmt.Errorf(\"cannot resolve member role id: %w\", err)\n\t}\n}\nrole, err := GetOrgMemberRoleId()","typeGuard":"func memberRoleCacheReady() bool {\n\treturn orgMemberRoleId != \"\"\n}","tryCatchPattern":null,"preventionTips":["Fail fast at startup if CacheOrgRoleIds leaves either global empty","Guard the globals with sync.Once/mutex to avoid reset races","Retry the cache fill inside the getter before failing"],"tags":["database","rbac","cache","state"],"backgroundTag":"empty-role-id-cache","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"}