{"record":{"id":"f6429104064f9ff9","repo":"RocketChat/Rocket.Chat","slug":"error-not-allowed-f64291","errorCode":"error-not-allowed","errorMessage":"Not allowed","messagePattern":"Not allowed","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/meteor-methods/messages/getSingleMessage.ts","lineNumber":24,"sourceCode":"\nimport { canAccessRoomIdAsync } from '../../lib/authorization/canAccessRoom';\n\ndeclare module '@rocket.chat/ddp-client' {\n\t// eslint-disable-next-line @typescript-eslint/naming-convention\n\tinterface ServerMethods {\n\t\tgetSingleMessage(mid: IMessage['_id']): Promise<IMessage | null>;\n\t}\n}\n\nexport const getSingleMessage = async (userId: string, mid: IMessage['_id']): Promise<IMessage | null> => {\n\tconst msg = await Messages.findOneById(mid);\n\n\tif (!msg?.rid) {\n\t\treturn null;\n\t}\n\n\tif (!(await canAccessRoomIdAsync(msg.rid, userId))) {\n\t\tthrow new Meteor.Error('error-not-allowed', 'Not allowed', { method: 'getSingleMessage' });\n\t}\n\n\treturn msg;\n};\n\nMeteor.methods<ServerMethods>({\n\tasync getSingleMessage(mid) {\n\t\tcheck(mid, String);\n\n\t\tconst uid = Meteor.userId();\n\n\t\tif (!uid) {\n\t\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', { method: 'getSingleMessage' });\n\t\t}\n\n\t\treturn getSingleMessage(uid, mid);\n\t},\n});","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/meteor-methods/messages/getSingleMessage.ts#L6-L42","documentation":"getSingleMessage loads the message and then checks canAccessRoomIdAsync(msg.rid, userId); failure throws 'error-not-allowed'. By this point the caller is authenticated and the message exists — the error means specifically: no access to the message's room (private channel / DM without a subscription, or membership revoked).","triggerScenarios":"Meteor.call('getSingleMessage', mid) for a message in a private channel or DM the caller has no subscription to.","commonSituations":"Deep links (jump-to-message) into private rooms; stale references after membership revocation; bots fetching messages from rooms they never joined.","solutions":["Ensure membership: join the room (or get invited) before fetching its messages","Hide or disable deep links to rooms the user is not subscribed to (check the local Subscriptions collection)","On error, surface a neutral 'message unavailable' response instead of retrying"],"exampleFix":"// before\nconst msg = await Meteor.callAsync('getSingleMessage', mid);\n\n// after\ntry {\n  const msg = await Meteor.callAsync('getSingleMessage', mid);\n} catch (e) {\n  if (e.error === 'error-not-allowed') {\n    // show 'message unavailable', do not retry\n  }\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const msg = await Meteor.callAsync('getSingleMessage', mid);\n} catch (e) {\n  if ((e as Meteor.Error).error === 'error-not-allowed') {\n    // message exists but its room is off-limits: show 'unavailable', never retry\n  }\n}","preventionTips":["Validate deep-linked rooms against the local Subscriptions collection before navigating","Drop cached references when the user loses room membership","Show a neutral 'message unavailable' instead of surfacing authorization details"],"tags":["meteor","authorization","rooms","messages"],"backgroundTag":"permission-denied","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}