{"record":{"id":"6703bdc4e5314ca4","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-team-not-a-member","errorCode":null,"errorMessage":"error-invalid-team-not-a-member","messagePattern":"error-invalid-team-not-a-member","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/services/team/service.ts","lineNumber":1099,"sourceCode":"\t\tuserId: string,\n\t\tteam: AtLeast<ITeam, '_id' | 'roomId' | 'type'>,\n\t\tfilter?: string,\n\t\ttype?: 'channels' | 'discussions',\n\t\tsort?: Record<string, 1 | -1>,\n\t\tskip = 0,\n\t\tlimit = 10,\n\t): Promise<{ total: number; data: IRoom[] }> {\n\t\tconst mainRoom = await Rooms.findOneById(team.roomId, { projection: { _id: 1 } });\n\t\tif (!mainRoom) {\n\t\t\tthrow new Error('error-invalid-team-no-main-room');\n\t\t}\n\n\t\tconst isMember = await TeamMember.findOneByUserIdAndTeamId(userId, team._id, {\n\t\t\tprojection: { _id: 1 },\n\t\t});\n\n\t\tif (!isMember) {\n\t\t\tthrow new Error('error-invalid-team-not-a-member');\n\t\t}\n\n\t\tconst [{ totalCount: [{ count: total }] = [], paginatedResults: data = [] }] =\n\t\t\t(await Rooms.findChildrenOfTeam(team._id, mainRoom._id, userId, filter, type, { skip, limit, sort }).toArray()) || [];\n\n\t\treturn {\n\t\t\ttotal,\n\t\t\tdata,\n\t\t};\n\t}\n}\n","sourceCodeStart":1081,"sourceCodeEnd":1111,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/e4b8178b205510181a96ceefee043d0abcd13e5a/apps/meteor/server/services/team/service.ts#L1081-L1111","documentation":"Thrown by TeamService.listChildren when the requesting user has no TeamMember document for the team — membership is checked with TeamMember.findOneByUserIdAndTeamId before listing team rooms. Team room listings (joined channels + public team channels + main-room discussions) are member-only. It fires after the main-room existence check.","triggerScenarios":"Listing rooms of a team the user never joined; the user was just removed but the client still shows the team; a script iterates all teams under one service account that belongs to none; membership records lost during migration.","commonSituations":"Stale UI after membership revocation; token reuse across users in tests; admin tooling using a non-member bot account.","solutions":["Verify membership first: TeamMember.findOneByUserIdAndTeamId(userId, teamId)","Re-fetch the user's teams (teams.list for the current user) and drop stale entries from the UI","Rejoin the team or request an invite if access is expected","For tooling, add the service account to the team before enumerating its rooms"],"exampleFix":"// before\nconst rooms = await Teams.listChildren(userId, team);\n\n// after\nconst isMember = await TeamMember.findOneByUserIdAndTeamId(userId, team._id, { projection: { _id: 1 } });\nif (!isMember) throw new Error('error-invalid-team-not-a-member');\nconst rooms = await Teams.listChildren(userId, team);","handlingStrategy":"validation","validationCode":"const isMember = await TeamMember.findOneByUserIdAndTeamId(userId, teamId, { projection: { _id: 1 } });\nif (!isMember) {\n  return API.v1.unauthorized(); // or hide the team from the user's listings\n}","typeGuard":null,"tryCatchPattern":"try {\n  const rooms = await Teams.listChildren(userId, team);\n} catch (err) {\n  if (err instanceof Error && err.message === 'error-invalid-team-not-a-member') {\n    // refresh the team list; remove the team from the sidebar\n  }\n  throw err;\n}","preventionTips":["Subscribe to membership-change events so the UI drops removed teams","Never reuse one user's credentials to enumerate another user's teams","Check membership in route guards before rendering team room lists"],"tags":["teams","authorization","membership"],"backgroundTag":"not-a-member","analyzedSha":"e4b8178b205510181a96ceefee043d0abcd13e5a","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}