{"record":{"id":"b9d822b2f7313d6b","repo":"RocketChat/Rocket.Chat","slug":"error-remove-last-owner","errorCode":"error-remove-last-owner","errorMessage":"This is the last owner. Please set a new owner before removing this one.","messagePattern":"This is the last owner\\. Please set a new owner before removing this one\\.","errorType":"exception","errorClass":"Meteor.Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/meteor-methods/rooms/removeRoomOwner.ts","lineNumber":63,"sourceCode":"\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) {\n\t\tvoid notifyOnSubscriptionChangedById(subscription._id);\n\t}\n\n\tconst fromUser = await Users.findOneById(fromUserId);\n\tif (!fromUser) {\n\t\tthrow new Meteor.Error('error-invalid-user', 'Invalid user', {\n\t\t\tmethod: 'removeRoomOwner',\n\t\t});","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/meteor-methods/rooms/removeRoomOwner.ts#L45-L81","documentation":"Business rule in removeRoomOwner: if Roles.countUsersInRole('owner', rid) === 1, the sole remaining owner cannot be demoted — error-remove-last-owner. This keeps rooms (and their teams) from becoming ownerless and unmanageable.","triggerScenarios":"Demoting the only owner of a channel; the previous co-owner already left so the target is the last one; ownership transfer scripted as remove-then-add instead of add-then-remove.","commonSituations":"Offboarding scripts stripping roles from a departing founder without promoting a successor first; teams where all other owners quit and were removed.","solutions":["Promote another member to owner FIRST (addRoomOwner / POST /api/v1/channels.addOwner), then remove the previous owner","If the room should not survive, delete the room instead of stripping its last owner","For teams, make sure a team owner remains before touching the main channel's ownership"],"exampleFix":"// before\nawait Meteor.callAsync('removeRoomOwner', rid, currentOwnerId);\n\n// after\nawait Meteor.callAsync('addRoomOwner', rid, newOwnerId);\nawait Meteor.callAsync('removeRoomOwner', rid, currentOwnerId);","handlingStrategy":"validation","validationCode":"// via REST: GET /api/v1/channels.roles?roomId=rid\n// count entries whose roles include 'owner'; only allow removal when count > 1\nconst ownerCount = (await fetchRoles(rid)).filter((r) => r.roles.includes('owner')).length;\nif (ownerCount < 2) {\n  // block: promote another owner first\n}","typeGuard":null,"tryCatchPattern":"try {\n  await Meteor.callAsync('removeRoomOwner', rid, userId);\n} catch (err) {\n  if (err instanceof Meteor.Error && err.error === 'error-remove-last-owner') {\n    // prompt user to select a successor, then addRoomOwner before retrying\n  }\n}","preventionTips":["Always transfer ownership as promote-then-demote, never demote-then-promote","Show a successor picker when only one owner remains","Offboarding scripts should verify an owner will remain before stripping roles"],"tags":["rooms","roles","ownership","business-rule"],"backgroundTag":"last-owner-protection","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}