{"record":{"id":"7b25077230ae1fcb","repo":"RocketChat/Rocket.Chat","slug":"error-user-not-owner","errorCode":"error-user-not-owner","errorMessage":"User is not an owner","messagePattern":"User is not an owner","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/meteor-methods/rooms/removeRoomOwner.ts","lineNumber":55,"sourceCode":"\t}\n\n\tconst user = await Users.findOneById(userId);\n\tif (!user?.username) {\n\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\tmethod: 'removeRoomOwner',\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-invalid-room', 'Invalid room', {\n\t\t\tmethod: 'removeRoomOwner',\n\t\t});\n\t}\n\n\tif (Array.isArray(subscription.roles) === false || subscription.roles?.includes('owner') === false) {\n\t\tthrow new Meteor.Error('error-user-not-owner', 'User is not an owner', {\n\t\t\tmethod: 'removeRoomOwner',\n\t\t});\n\t}\n\n\tconst numOwners = await Roles.countUsersInRole('owner', rid);\n\n\tif (numOwners === 1) {\n\t\tthrow new Meteor.Error('error-remove-last-owner', 'This is the last owner. Please set a new owner before removing this one.', {\n\t\t\tmethod: 'removeRoomOwner',\n\t\t});\n\t}\n\n\tawait beforeChangeRoomRole.run({ fromUserId, userId, room, role: 'user' });\n\n\tconst removeRoleResponse = await Subscriptions.removeRoleById(subscription._id, 'owner');\n\tawait syncRoomRolePriorityForUserAndRoom(userId, rid, subscription.roles?.filter((r) => r !== 'owner') || []);\n\n\tif (removeRoleResponse.modifiedCount) {","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/meteor-methods/rooms/removeRoomOwner.ts#L37-L73","documentation":"removeRoomOwner requires the target's subscription.roles to be an array that includes 'owner'; otherwise it throws error-user-not-owner. Unlike the moderator check, this one also fires when roles is undefined or missing entirely.","triggerScenarios":"Calling removeRoomOwner on a plain member or a moderator; the owner role was already removed by another admin; subscription.roles missing entirely.","commonSituations":"Stale 'Owner' badge in a members modal after the role was stripped elsewhere; racing double-invocations of the action.","solutions":["Inspect the target's subscription roles and only offer 'Remove owner' when they include 'owner'","Refresh the member/roles list right before rendering actions","Catch error-user-not-owner and treat it as 'already demoted'"],"exampleFix":"// before\nawait Meteor.callAsync('removeRoomOwner', rid, userId);\n\n// after\nconst sub = Subscriptions.findOne({ rid, 'u._id': userId });\nconst roles = sub?.roles;\nif (!Array.isArray(roles) || !roles.includes('owner')) return;\nawait Meteor.callAsync('removeRoomOwner', rid, userId);","handlingStrategy":"type-guard","validationCode":"const sub = Subscriptions.findOne({ rid, 'u._id': userId });\nif (!Array.isArray(sub?.roles) || !sub.roles.includes('owner')) {\n  // not an owner: skip removal\n}","typeGuard":"const hasRoomRole = (roles: string[] | undefined | null, role: string): boolean =>\n  Array.isArray(roles) && roles.includes(role);\n\nconst isOwner = (sub?: { roles?: string[] }): boolean => hasRoomRole(sub?.roles, 'owner');","tryCatchPattern":"try {\n  await Meteor.callAsync('removeRoomOwner', rid, userId);\n} catch (err) {\n  if (err instanceof Meteor.Error && err.error === 'error-user-not-owner') {\n    // already demoted: refresh and continue\n  }\n}","preventionTips":["Render 'Remove owner' only when subscription roles include owner","Refresh roles data before actions","Note this check also fires when roles is missing entirely — stricter than the moderator variant"],"tags":["roles","subscriptions","rooms","meteor-methods"],"backgroundTag":"role-not-assigned","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","contentChangedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}