RocketChat/Rocket.Chat · error · Meteor.Error
error-cannot-delete-team-channel
error-cannot-delete-team-channel
Error message
Cannot delete a team channel
What it means
Thrown by DELETE/POST rooms.eraseRoom when the target room has its 'teamMain' flag set. Rocket.Chat teams own one primary channel that anchors the team; deleting it would orphan the team, so the server refuses. To remove it you must delete the whole team, not the channel in isolation.
Source
Thrown at apps/meteor/server/api/v1/rooms.ts:208
additionalProperties: false,
}),
400: validateBadRequestErrorResponse,
401: validateUnauthorizedErrorResponse,
},
},
async function action() {
const { roomId } = this.bodyParams;
const room = await Rooms.findOneById(roomId);
if (!room) {
throw new MeteorError('error-invalid-room', 'Invalid room', {
method: 'eraseRoom',
});
}
if (room.teamMain) {
throw new Meteor.Error('error-cannot-delete-team-channel', 'Cannot delete a team channel', {
method: 'eraseRoom',
});
}
await eraseRoom(room, this.user);
return API.v1.success();
},
);
API.v1.get(
'rooms.get',
{
authRequired: true,
response: {
200: ajv.compile<{ update: IRoom[]; remove: IRoom[] }>({
type: 'object',
properties: {View on GitHub (pinned to f9d3ec372b)
Solutions
- If you want the team gone, delete the team (teams.delete / team removal flow) instead of the single channel.
- If you must remove the channel, first convert the team so this room is no longer teamMain (remove the team association), then call eraseRoom.
- Pre-check room.teamMain via rooms.info or rooms.get before calling eraseRoom and skip or branch accordingly.
- Filter team-main rooms out of any bulk-delete job.
Example fix
// before
await rest.post('/api/v1/rooms.eraseRoom', { roomId });
// after
const info = await rest.get(`/api/v1/rooms.info?roomId=${roomId}`);
if (info.room.teamMain) {
// delete the owning team instead, or unteam the channel first
await rest.post('/api/v1/teams.delete', { teamName: info.room.teamId });
} else {
await rest.post('/api/v1/rooms.eraseRoom', { roomId });
} Defensive patterns
Strategy: validation
Validate before calling
const info = await rest.get(`/api/v1/rooms.info?roomId=${roomId}`);
if (info.room?.teamMain) {
// do NOT call eraseRoom; delete the team instead
throw new Error(`Room ${roomId} is a team's main channel; delete via teams.delete`);
} Type guard
function isTeamMainRoom(r: { teamMain?: boolean } | undefined | null): boolean {
return !!r?.teamMain;
} Try / catch
try {
await rest.post('/api/v1/rooms.eraseRoom', { roomId });
} catch (e) {
if (isMeteorError(e, 'error-cannot-delete-team-channel')) {
// fall back to deleting the owning team
} else throw e;
} Prevention
- Pre-filter bulk delete lists by room.teamMain === false.
- Surface team-main status in the delete-confirm UI and disable the button.
- Document that team channels are deleted only through the teams API.
When it happens
Trigger: POST /api/v1/rooms.eraseRoom with { roomId } where that room is the main channel of a team (room.teamMain === true). Also reached by any internal caller invoking the eraseRoom action handler after the room is loaded and the teamMain check runs.
Common situations: Migration/cleanup scripts that naively iterate all rooms and delete them; converting a team back into ordinary channels; admin tooling that doesn't account for teams; CI that creates a team then tries to tear it down room-by-room.
Related errors
- Room not found
- error-room-param-not-provided
- error-room-not-found
- error-roomid-param-not-provided
- error-room-not-found
AI-assisted analysis of RocketChat/Rocket.Chat@f9d3ec372b (2026-08-12).
Data as JSON: /api/errors/ec1055a07f278eb9.
Report an issue: GitHub.