{"record":{"id":"54f8d873bd2dfac0","repo":"RocketChat/Rocket.Chat","slug":"error-not-allowed-54f8d8","errorCode":"error-not-allowed","errorMessage":"Not Allowed","messagePattern":"Not Allowed","errorType":"error_code","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/api/v1/groups.ts","lineNumber":1298,"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 hidden = await getUsersHiddenFrom(this.userId);\n\n\t\tconst online: Pick<IUser, '_id' | 'username'>[] = filterHiddenUsers(\n\t\t\tawait Users.findUsersNotOffline({\n\t\t\t\tprojection: {\n\t\t\t\t\tusername: 1,\n\t\t\t\t},\n\t\t\t}).toArray(),\n\t\t\thidden,\n\t\t);\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});","sourceCodeStart":1280,"sourceCodeEnd":1316,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/e4b8178b205510181a96ceefee043d0abcd13e5a/apps/meteor/server/api/v1/groups.ts#L1280-L1316","documentation":"Thrown by GET groups.online when the caller cannot access the resolved private group: canAccessRoomAsync(room, this.user) returns false. groups.online lists online members of a group, and for private groups the caller must be a member (or hold access-granting permission/ABAC attributes). Note this endpoint returns 'Group does not exists' as a plain failure for a missing room, but a real room without access raises this error-not-allowed Meteor error.","triggerScenarios":"GET groups.online?roomId=<private group id> with a token whose user is not in that group; a bot account asked to monitor online users of an exclusive/secret group it was never invited to; access revoked (user kicked) while their client keeps polling presence.","commonSituations":"Presence dashboards built on service accounts that are not group members; permission model changes (ABAC rollout) silently revoking implicit access; monitoring tooling working for public channels but pointed at private groups.","solutions":["Add the calling account to the group (groups.invite by an owner) or use an account with room-administration access rights","Scope monitoring to rooms the service account is a member of; expose group membership lists to it explicitly","Handle this error distinctly from 'Group does not exists' - it means access denied, not absent"],"exampleFix":"// before\nconst { online } = await botSdk.get('groups.online', { roomId: secretGroupId }); // bot not a member\n\n// after\nawait ownerSdk.post('groups.invite', { roomId: secretGroupId, username: botUsername });\nconst { online } = await botSdk.get('groups.online', { roomId: secretGroupId });","handlingStrategy":"try-catch","validationCode":"// cheap pre-flight with the same token: only poll groups.online for rooms the token can see\nconst visible = await sdk.get('rooms.info', { roomId }).catch(() => null);\nif (!visible) throw new Error('token cannot access this group');","typeGuard":null,"tryCatchPattern":"try {\n  const { online } = await sdk.get('groups.online', { roomId });\n} catch (e) {\n  if (e.error === 'error-not-allowed') {\n    // access denied for this private group: stop polling it with this token, alert operator\n  } else if (e.errorType === 'error' || /does not exists/.test(String(e.message))) {\n    // distinct branch: room genuinely missing\n  }\n}","preventionTips":["Give presence/monitoring service accounts explicit membership in every group they watch","Distinguish this error from the plain 'Group does not exists' failure - different remedies","Re-check access after kicks/permission changes instead of letting polls fail forever"],"tags":["rest-api","groups","authorization","presence","room-access"],"backgroundTag":"room-access-denied","analyzedSha":"e4b8178b205510181a96ceefee043d0abcd13e5a","analyzedAt":"2026-09-08T13:24:24.891Z","contentChangedAt":"2026-09-08T13:24:24.891Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}