{"record":{"id":"5808b86032b2060d","repo":"RocketChat/Rocket.Chat","slug":"error-encrypted-private-rooms-enforced-discussion","errorCode":"error-encrypted-private-rooms-enforced-discussion","errorMessage":"Workspace policy requires all private rooms to be encrypted. To create this discussion, make the parent channel public or enable encryption on it.","messagePattern":"Workspace policy requires all private rooms to be encrypted\\. To create this discussion, make the parent channel public or enable encryption on it\\.","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/meteor-methods/messages/createDiscussion.ts","lineNumber":160,"sourceCode":"\tconst invitedUsers = message ? [message.u.username, ...users] : users;\n\n\tconst type = await roomCoordinator.getRoomDirectives(parentRoom.t).getDiscussionType(parentRoom);\n\tconst description = parentRoom.encrypted ? '' : message?.msg;\n\tconst discussionTopic = topic || parentRoom.name;\n\n\tif (!type) {\n\t\tthrow new Meteor.Error('error-invalid-type', 'Cannot define discussion room type', {\n\t\t\tmethod: 'DiscussionCreation',\n\t\t});\n\t}\n\n\tif (\n\t\ttype === 'p' &&\n\t\t!encrypted &&\n\t\tsettings.get<boolean>('E2E_Enable') &&\n\t\tsettings.get<boolean>('E2E_Force_Encryption_For_Private_Rooms')\n\t) {\n\t\tthrow new Meteor.Error(\n\t\t\t'error-encrypted-private-rooms-enforced-discussion',\n\t\t\t'Workspace policy requires all private rooms to be encrypted. To create this discussion, make the parent channel public or enable encryption on it.',\n\t\t\t{ method: 'DiscussionCreation' },\n\t\t);\n\t}\n\n\tconst discussion = await createRoom(\n\t\ttype,\n\t\tname,\n\t\tuser,\n\t\t[...new Set(invitedUsers)].filter(Boolean),\n\t\tfalse,\n\t\tfalse,\n\t\t{\n\t\t\tfname: discussionName,\n\t\t\tdescription, // TODO discussions remove\n\t\t\ttopic: discussionTopic,\n\t\t\tprid,","sourceCodeStart":142,"sourceCodeEnd":178,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/2a7de457074cbb4d4373fbd9a4e5bea292c9c764/apps/meteor/server/meteor-methods/messages/createDiscussion.ts#L142-L178","documentation":"Thrown by the createDiscussion server flow when the resolved discussion type is private ('p', inherited from a private parent channel via roomCoordinator.getDiscussionType), the effective encrypted flag is false, and the workspace enforces E2E_Enable plus E2E_Force_Encryption_For_Private_Rooms. Discussions inherit encryption from the parent room (createDiscussion.ts:116-118 defaults encrypted to Boolean(parentRoom.encrypted)), so an unencrypted private parent would produce an unencrypted private discussion, which the policy forbids. Passing encrypted: true explicitly bypasses this check, but then the call must omit reply, because encrypted discussions reject initial replies (createDiscussion.ts:120 throws error-invalid-arguments).","triggerScenarios":"Meteor method createDiscussion (deprecated in 9.0.0 in favor of POST /v1/rooms.createDiscussion) with prid/pmid pointing at a private, unencrypted channel while E2E_Enable and E2E_Force_Encryption_For_Private_Rooms are both true — either with no encrypted argument (inherits false from the parent) or with an explicit encrypted:false. The check fires after type resolution and after the reply/encrypted mutual-exclusion check.","commonSituations":"An admin flips on forced encryption on an existing workspace where users already have private unencrypted channels — every 'Create discussion' action on those channels now fails until parents are encrypted. Also hit by REST integrations that never send the encrypted field for private parents, or when replaying a createDiscussion payload recorded on a non-E2E workspace against an E2E-enforcing one.","solutions":["Enable E2E encryption on the parent private channel first (room header → Encryption), then retry — the discussion inherits encrypted=true and passes.","Pass encrypted: true in the createDiscussion call so the discussion itself is E2E even though the parent is not; you must also omit the reply field, since encrypted discussions cannot take an initial reply.","Make the parent channel public (type 'c') and retry — public rooms sit outside the force-encryption policy.","Or have a workspace admin disable E2E_Force_Encryption_For_Private_Rooms if unencrypted private discussions must remain possible."],"exampleFix":"// before — parent room is private + unencrypted, policy enabled → throws\n// error-encrypted-private-rooms-enforced-discussion\nawait Meteor.callAsync('createDiscussion', {\n  prid: 'parentRoomId', t_name: 'Sprint sync', users: ['alice'], reply: 'kickoff',\n});\n\n// after — opt the discussion into E2E explicitly and drop the initial reply\nawait Meteor.callAsync('createDiscussion', {\n  prid: 'parentRoomId', t_name: 'Sprint sync', users: ['alice'], encrypted: true,\n});","handlingStrategy":"validation","validationCode":"import { Rooms } from '@rocket.chat/models';\nimport { settings } from '../../settings';\n\nconst privateDiscussionBlockedByPolicy = async (\n  prid: string,\n  encrypted?: boolean,\n): Promise<boolean> => {\n  const parent = await Rooms.findOneById(prid, { projection: { t: 1, encrypted: 1 } });\n  if (!parent || parent.t !== 'p') return false; // only private parents get a 'p' discussion\n  const effectiveEncrypted = typeof encrypted === 'boolean' ? encrypted : Boolean(parent.encrypted);\n  return (\n    !effectiveEncrypted &&\n    settings.get<boolean>('E2E_Enable') === true &&\n    settings.get<boolean>('E2E_Force_Encryption_For_Private_Rooms') === true\n  );\n};\n\nif (await privateDiscussionBlockedByPolicy(prid, encrypted)) {\n  // encrypt the parent, pass encrypted: true (with no reply), or block the action in the UI\n}","typeGuard":null,"tryCatchPattern":"try {\n  await Meteor.callAsync('createDiscussion', { prid, t_name, users });\n} catch (error) {\n  if (error instanceof Meteor.Error && error.error === 'error-encrypted-private-rooms-enforced-discussion') {\n    // offer the user the two policy-compliant paths: encrypt the parent channel,\n    // or retry with encrypted: true (and no initial reply)\n    return Meteor.callAsync('createDiscussion', { prid, t_name, users, encrypted: true });\n  }\n  throw error;\n}","preventionTips":["Never force encrypted:false for discussions — omit the field and inherit encryption from the parent room.","When the policy is on, disable the discussion-creation affordance on private unencrypted parents, or preselect encrypted:true.","Encrypted discussions cannot receive an initial reply — whenever you pass encrypted:true, drop the reply argument (a separate error-invalid-arguments is thrown otherwise).","Verify pmid belongs to prid before calling; adjacent argument mismatches throw their own errors earlier in the same method."],"tags":["e2e","encryption","discussions","workspace-policy","private-channels","rocket-chat"],"backgroundTag":"e2e-encryption-policy","analyzedSha":"2a7de457074cbb4d4373fbd9a4e5bea292c9c764","analyzedAt":"2026-08-21T15:01:34.830Z","contentChangedAt":"2026-08-21T15:01:34.830Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}