{"record":{"id":"75b8058f7b6cdb9b","repo":"RocketChat/Rocket.Chat","slug":"error-user-not-in-room-75b805","errorCode":"error-user-not-in-room","errorMessage":"User is not in this room","messagePattern":"User is not in this room","errorType":"error_code","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/meteor-methods/rooms/addRoomOwner.ts","lineNumber":58,"sourceCode":"\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\n\tif (!subscription) {\n\t\tthrow new Meteor.Error('error-user-not-in-room', 'User is not in this room', {\n\t\t\tmethod: 'addRoomOwner',\n\t\t});\n\t}\n\n\tif (subscription.roles && Array.isArray(subscription.roles) === true && subscription.roles.includes('owner') === true) {\n\t\tthrow new Meteor.Error('error-user-already-owner', 'User is already an owner', {\n\t\t\tmethod: 'addRoomOwner',\n\t\t});\n\t}\n\n\tawait beforeChangeRoomRole.run({ fromUserId, userId, room, role: 'owner' });\n\n\tconst addRoleResponse = await Subscriptions.addRoleById(subscription._id, 'owner');\n\tawait syncRoomRolePriorityForUserAndRoom(userId, rid, subscription.roles?.concat(['owner']) || ['owner']);\n\n\tif (addRoleResponse.modifiedCount) {\n\t\tvoid notifyOnSubscriptionChangedById(subscription._id);\n\t}","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/meteor-methods/rooms/addRoomOwner.ts#L40-L76","documentation":"Thrown by addRoomOwner() in apps/meteor/server/meteor-methods/rooms/addRoomOwner.ts:58 when Subscriptions.findOneByRoomIdAndUserId(rid, user._id) returns null — the target user exists but has no subscription for that room, i.e. is not a member. Rocket.Chat roles like 'owner' are stored on the room subscription, so promoting a non-member is impossible.","triggerScenarios":"Calling addRoomOwner for a user who never joined or was never invited; the user left the room or was kicked before the promotion; the user was removed when the room was converted to a private team channel; racing with a concurrent leave/remove operation.","commonSituations":"Admin scripts promoting users by a list that predates a room cleanup; UI flows where the operator types a username not currently in the channel; ops run right after a mass-remove of inactive members; stale membership assumptions after team/channel conversion.","solutions":["Check membership first: const sub = await Subscriptions.findOneByRoomIdAndUserId(rid, userId); and require sub before promoting.","If the user should be a member, add them first (e.g. POST /v1/channels.invite or the addUsersToRoom flow), then grant 'owner'.","If they were removed by mistake, re-invite and retry.","Prefer the REST endpoints POST /v1/channels.addOwner / POST /v1/groups.addOwner which validate membership with clearer API error bodies."],"exampleFix":"// before\nawait addRoomOwner(uid, rid, targetUserId);\n\n// after\nconst sub = await Subscriptions.findOneByRoomIdAndUserId(rid, targetUserId, { projection: { _id: 1 } });\nif (!sub) throw new Error('target is not a member of the room; invite first');\nawait addRoomOwner(uid, rid, targetUserId);","handlingStrategy":"validation","validationCode":"const sub = await Subscriptions.findOneByRoomIdAndUserId(rid, userId, { projection: { _id: 1 } });\nif (!sub) throw new Error('target is not a member; invite before promoting');","typeGuard":"const isMember = (s: unknown): s is { _id: string } => Boolean(s && typeof (s as any)?._id === 'string');","tryCatchPattern":"try {\n  await addRoomOwner(uid, rid, userId);\n} catch (e) {\n  if (e instanceof Meteor.Error && e.error === 'error-user-not-in-room') {\n    // invite the user first, then retry the promotion\n  }\n}","preventionTips":["Gate promote/owner UI on the membership list of the room, not a global user picker.","For bulk scripts, diff desired owners against current subscriptions first.","Re-check membership immediately before the call in flows where users may leave concurrently."],"tags":["meteor-method","subscriptions","membership","rooms"],"backgroundTag":"user-not-in-room","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}