RocketChat/Rocket.Chat · error · Meteor.Error

error-duplicate-channel-name

error-duplicate-channel-name

Error message

A channel with name '${cleanName}' exists

What it means

Same special-chars path as its archived sibling, but the conflicting room (same display name, different _id) is live, so creation/rename is refused with error-duplicate-channel-name. Contrast the lower branch of the same function: in the non-special-chars path Rocket.Chat auto-appends -2, -3… suffixes instead of throwing — throwing on duplicates only happens for display-name matches when UI_Allow_room_names_with_special_chars is on.

Source

Thrown at apps/meteor/server/lib/utils/lib/getValidRoomName.ts:23

import { settings } from '../../../settings';
import { validateName } from '../../shared/validateName';

export const getValidRoomName = async (displayName: string, rid = '', options: { allowDuplicates?: boolean } = {}) => {
	let slugifiedName = displayName;

	if (settings.get('UI_Allow_room_names_with_special_chars')) {
		const cleanName = limax(displayName, { maintainCase: true });
		if (options.allowDuplicates !== true) {
			const room = await Rooms.findOneByDisplayName(displayName);
			if (room && room._id !== rid) {
				if (room.archived) {
					throw new Meteor.Error('error-archived-duplicate-name', `There's an archived channel with name ${cleanName}`, {
						function: 'RocketChat.getValidRoomName',
						channel_name: cleanName,
					});
				} else {
					throw new Meteor.Error('error-duplicate-channel-name', `A channel with name '${cleanName}' exists`, {
						function: 'RocketChat.getValidRoomName',
						channel_name: cleanName,
					});
				}
			}
		}
		slugifiedName = cleanName;
	}

	let nameValidation;

	try {
		nameValidation = new RegExp(`^${settings.get('UTF8_Channel_Names_Validation')}$`);
	} catch (error) {
		nameValidation = new RegExp('^[0-9a-zA-Z-_.]+$');
	}

	if (!nameValidation.test(slugifiedName) || !validateName(slugifiedName)) {

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Choose a different display name
  2. Pass { allowDuplicates: true } when the caller's semantics allow same display names (slugs still differ)
  3. Rename or delete the existing live channel first if consolidation is intended

Example fix

// before
await getValidRoomName('general'); // live channel named 'general' exists

// after
await getValidRoomName('general', '', { allowDuplicates: true });
// or pick a distinct name
await getValidRoomName('general-eng');
Defensive patterns

Strategy: validation

Validate before calling

import { Rooms } from '@rocket.chat/models';

const existing = await Rooms.findOneByDisplayName(displayName);
if (existing && existing._id !== rid && !existing.archived) {
  // name taken by a live room: block or suggest alternatives
}

Try / catch

try {
  await getValidRoomName(name, rid);
} catch (error) {
  if (error instanceof Meteor.Error && error.error === 'error-duplicate-channel-name') {
    // suggest name variants (name-2, name-team)
  } else {
    throw error;
  }
}

Prevention

When it happens

Trigger: Creating or renaming a channel to the display name of an active channel (UI_Allow_room_names_with_special_chars on, allowDuplicates !== true).

Common situations: Common channel names ('general', 'random', 'announcements'); parallel departments naming channels identically; imports colliding with existing rooms.

Related errors


AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18). Data as JSON: /api/errors/e7dbb0dace373bcf. Report an issue: GitHub.