{"record":{"id":"54f8d873bd2dfac0","repo":"RocketChat/Rocket.Chat","slug":"error-not-allowed-54f8d8","errorCode":"error-not-allowed","errorMessage":"Not Allowed","messagePattern":"Not Allowed","errorType":"exception","errorClass":"Meteor.Error","httpStatus":403,"severity":"error","filePath":"apps/meteor/server/api/v1/groups.ts","lineNumber":1294,"sourceCode":"\t\tconst { _id } = this.queryParams;\n\n\t\tif ((!query || Object.keys(query).length === 0) && !_id) {\n\t\t\treturn API.v1.failure('Invalid query');\n\t\t}\n\n\t\tconst filter = {\n\t\t\t...query,\n\t\t\t...(_id ? { _id } : {}),\n\t\t\tt: 'p',\n\t\t};\n\n\t\tconst room = await Rooms.findOne(filter as Record<string, any>);\n\t\tif (!room) {\n\t\t\treturn API.v1.failure('Group does not exists');\n\t\t}\n\n\t\tif (!(await canAccessRoomAsync(room, this.user))) {\n\t\t\tthrow new Meteor.Error('error-not-allowed', 'Not Allowed');\n\t\t}\n\n\t\tconst online: Pick<IUser, '_id' | 'username'>[] = await Users.findUsersNotOffline({\n\t\t\tprojection: {\n\t\t\t\tusername: 1,\n\t\t\t},\n\t\t}).toArray();\n\n\t\tconst onlineInRoom = await Promise.all(\n\t\t\tonline.map(async (user) => {\n\t\t\t\tconst subscription = await Subscriptions.findOneByRoomIdAndUserId(room._id, user._id, {\n\t\t\t\t\tprojection: { _id: 1, username: 1 },\n\t\t\t\t});\n\t\t\t\tif (subscription) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\t_id: user._id,\n\t\t\t\t\t\tusername: user.username,\n\t\t\t\t\t};","sourceCodeStart":1276,"sourceCodeEnd":1312,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/f9d3ec372bb580fa8d036f94cf03925a478ef768/apps/meteor/server/api/v1/groups.ts#L1276-L1312","documentation":"Thrown by groups.online (groups.ts:1293-1295). The room was found by query/_id and is a private group (t:'p'), but canAccessRoomAsync(room, this.user) returned false: the caller is not a member and lacks an override permission that grants visibility into the group's online roster. This is the authorization gate; it surfaces as a generic 'Not Allowed' (403-shaped) so as not to confirm the room's existence.","triggerScenarios":"GET groups.online with a valid query/_id for a private group while the authenticated user is neither a member nor a moderator/admin with an override (e.g. 'view-room-administration' / 'view-all-rooms').","commonSituations":"A dashboard/bot tries to report online members for groups it does not belong to. A user navigates to a private group's online list without having joined. Tests querying as an uninvited user.","solutions":["Ensure the caller is a member of the group, or use a token whose user has the appropriate override permission (e.g. view-room-administration) that canAccessRoomAsync accepts.","Have a member/admin invite the calling user (groups.invite) before requesting online status.","If presence is needed broadly, prefer a presence/subscription endpoint the user is authorized for rather than groups.online on private rooms.","Confirm the authenticated token corresponds to the user you expect (stale tokens of ex-members fail here)."],"exampleFix":"// before\nawait GET('/api/v1/groups.online', { query: { _id: groupId } }); // caller not a member -> 403 error-not-allowed\n\n// after\nconst me = await GET('/api/v1/me');\nif (!await isMember(groupId, me.userId)) {\n  // have a member invite `me.userId` first, or use an admin token with view-room-administration\n  await POST('/api/v1/groups.invite', { roomId: groupId, userId: me.userId });\n}\nawait GET('/api/v1/groups.online', { query: { _id: groupId } });","handlingStrategy":"validation","validationCode":"// Pre-flight: confirm caller access to the private group before requesting online roster.\nconst info = await api.get('/api/v1/groups.info', { roomId }).catch(() => null);\nif (!info) throw new Error('No access or no such group');\nawait api.get('/api/v1/groups.online', { query: { _id: roomId } });","typeGuard":"function isPrivateGroup(r) {\n  return r != null && r.t === 'p';\n}","tryCatchPattern":"try {\n  await api.get('/api/v1/groups.online', { query: { _id: roomId } });\n} catch (e) {\n  if (isMeteorError(e) && e.reason === 'error-not-allowed') {\n    // caller lacks access; invite the caller or use an authorized service token\n  }\n  throw e;\n}","preventionTips":["Ensure the calling user is a member or holds view-room-administration.","Revoke tokens of ex-members promptly.","For bots reporting presence, scope them to groups they belong to.","Use presence endpoints the user is authorized for rather than groups.online on others' rooms."],"tags":["rest-api","groups","online","authorization","access-control"],"backgroundTag":null,"analyzedSha":"f9d3ec372bb580fa8d036f94cf03925a478ef768","analyzedAt":"2026-08-12T19:07:17.372Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}