{"record":{"id":"d318a2381467304b","repo":"RocketChat/Rocket.Chat","slug":"error-not-allowed-d318a2","errorCode":"error-not-allowed","errorMessage":"Not allowed","messagePattern":"Not allowed","errorType":"error_code","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/meteor-methods/rooms/addRoomOwner.ts","lineNumber":38,"sourceCode":"\t\taddRoomOwner(rid: IRoom['_id'], userId: IUser['_id']): boolean;\n\t}\n}\n\nexport const addRoomOwner = async (fromUserId: IUser['_id'], rid: IRoom['_id'], userId: IUser['_id']): Promise<boolean> => {\n\tcheck(rid, String);\n\tcheck(userId, String);\n\n\tconst room = await Rooms.findOneById(rid, { projection: { t: 1, federated: 1, federation: 1 } });\n\tif (!room) {\n\t\tthrow new Meteor.Error('error-invalid-room', 'Invalid room', {\n\t\t\tmethod: 'addRoomOwner',\n\t\t});\n\t}\n\n\tconst isFederated = isRoomFederated(room);\n\n\tif (!(await hasPermissionAsync(fromUserId, 'set-owner', rid)) && !isFederated) {\n\t\tthrow new Meteor.Error('error-not-allowed', 'Not allowed', {\n\t\t\tmethod: 'addRoomOwner',\n\t\t});\n\t}\n\n\tif (isFederated && !isFederationEnabled()) {\n\t\tthrow new FederationMatrixInvalidConfigurationError('unable to change room owners');\n\t}\n\n\tconst user = await Users.findOneById(userId);\n\n\tif (!user?.username) {\n\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\tmethod: 'addRoomOwner',\n\t\t});\n\t}\n\n\tconst subscription = await Subscriptions.findOneByRoomIdAndUserId(rid, user._id);\n","sourceCodeStart":20,"sourceCodeEnd":56,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/meteor-methods/rooms/addRoomOwner.ts#L20-L56","documentation":"Thrown by addRoomOwner() in apps/meteor/server/meteor-methods/rooms/addRoomOwner.ts:38 when the acting user lacks the 'set-owner' permission for that room AND the room is not federated (isRoomFederated(room) === false). It is the authorization gate for granting the 'owner' role; federation is exempted here because Matrix-sourced ownership changes follow a separate path (guarded further down by FederationMatrixInvalidConfigurationError).","triggerScenarios":"A non-admin without 'set-owner' (globally or scoped to the rid) calls 'addRoomOwner'; an admin whose 'set-owner' permission was revoked or scoped to another room; permission changes not yet propagated to the acting session; calling with a fromUserId of a bot/service account that never received the role.","commonSituations":"Custom role setups where 'set-owner' was removed from the admin role; workspace owners assuming global admin implies per-room permissions after a permission refactor; scripts running as a low-privilege system user; role hierarchies where the target's role priority rules block the action but the permission check fails first.","solutions":["Grant 'set-owner' to the acting user (globally or scoped to the room) via Administration > Permissions, then retry.","Verify the permission programmatically before calling: await hasPermissionAsync(fromUserId, 'set-owner', rid).","Confirm you are passing the intended fromUserId — the check uses fromUserId, not the logged-in user, in the exported helper.","If the room is federated on purpose but reports as non-federated, verify the room's federation fields were set when it was created."],"exampleFix":"// before\nawait addRoomOwner(uid, rid, targetUserId);\n\n// after\nif (!(await hasPermissionAsync(uid, 'set-owner', rid))) {\n  throw new Error('missing set-owner permission for this room');\n}\nawait addRoomOwner(uid, rid, targetUserId);","handlingStrategy":"validation","validationCode":"const canSetOwner = await hasPermissionAsync(uid, 'set-owner', rid);\nif (!canSetOwner) throw new Error('missing set-owner permission');","typeGuard":null,"tryCatchPattern":"try {\n  await addRoomOwner(uid, rid, userId);\n} catch (e) {\n  if (e instanceof Meteor.Error && e.error === 'error-not-allowed') {\n    // surface 'you need set-owner permission' to the user; do not retry\n  }\n}","preventionTips":["Pre-check hasPermissionAsync(uid, 'set-owner', rid) before enabling the UI action.","Scope permissions per room when granting set-owner so cross-room abuse is limited.","In jobs, run as an account that provably holds the needed role."],"tags":["meteor-method","permissions","authorization","rooms"],"backgroundTag":"insufficient-permissions","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}