RocketChat/Rocket.Chat · error · Meteor.Error
error-duplicate-handle
error-duplicate-handle
Error message
A room, team or user with name '${slugifiedRoomName}' already exists What it means
Thrown by updateRoomName inside saveRoomName when checkUsernameAvailability(slugifiedRoomName, 'room') returns false (saveRoomName.ts:27) — the slugified target name collides with an existing room, team, or user handle, since these share one namespace. slugifiedRoomName comes from getValidRoomName(displayName, rid); the error embeds the offending handle in details { handle }. Code 'error-duplicate-handle'.
Source
Thrown at apps/meteor/server/lib/rooms/settings/saveRoomName.ts:27
import { notifyOnIntegrationChangedByChannels, notifyOnSubscriptionChangedByRoomId } from '../../notifyListener';
import { checkUsernameAvailability } from '../../users/checkUsernameAvailability';
import { getValidRoomName } from '../../utils/lib/getValidRoomName';
import { roomCoordinator } from '../roomCoordinator';
const updateFName = async (rid: string, displayName: string): Promise<(UpdateResult | Document)[]> => {
const responses = await Promise.all([Rooms.setFnameById(rid, displayName), Subscriptions.updateFnameByRoomId(rid, displayName)]);
if (responses[1]?.modifiedCount) {
void notifyOnSubscriptionChangedByRoomId(rid);
}
return responses;
};
const updateRoomName = async (rid: string, displayName: string, slugifiedRoomName: string) => {
// Check if the name is available
if (!(await checkUsernameAvailability(slugifiedRoomName, 'room'))) {
throw new Meteor.Error('error-duplicate-handle', `A room, team or user with name '${slugifiedRoomName}' already exists`, {
function: 'RocketChat.updateRoomName',
handle: slugifiedRoomName,
});
}
const responses = await Promise.all([
Rooms.setNameById(rid, slugifiedRoomName, displayName),
Subscriptions.updateNameAndAlertByRoomId(rid, slugifiedRoomName, displayName),
]);
if (responses[1]?.modifiedCount) {
void notifyOnSubscriptionChangedByRoomId(rid);
}
return responses;
};
export async function saveRoomName(View on GitHub (pinned to b2c16d5842)
Solutions
- Pick a different display name — the message names the exact conflicting handle
- Rename or delete the conflicting user/room/team that owns the handle, if that object is the disposable one
- Pre-check availability before offering the rename: await checkUsernameAvailability(slugified, 'room')
- For programmatic renames, retry with a suffixed name (name-2) since a concurrent creator may have claimed the handle
Example fix
// before
await saveRoomName(rid, 'support', user);
// after
const slug = await getValidRoomName('support', rid);
if (!(await checkUsernameAvailability(slug, 'room'))) {
throw new Meteor.Error('error-duplicate-handle', `A room, team or user with name '${slug}' already exists`);
}
await saveRoomName(rid, 'support', user); Defensive patterns
Strategy: validation
Validate before calling
const slugified = await getValidRoomName(displayName, rid);
if (!(await checkUsernameAvailability(slugified, 'room'))) {
throw new Meteor.Error('error-duplicate-handle', `Name '${slugified}' is taken by a room, team or user`);
}
await saveRoomName(rid, displayName, user); Try / catch
try {
await saveRoomName(rid, displayName, user);
} catch (e) {
if (e instanceof Meteor.Error && e.error === 'error-duplicate-handle') {
// e.details.handle names the conflict; prompt for another name or auto-suffix
}
} Prevention
- Remember users, rooms and teams share one handle namespace — check all three before offering a name
- For programmatic renames, fall back to name-2, name-3 on this error
- Check availability right before the rename, not when the form loads, to shrink the race window
When it happens
Trigger: Renaming a channel to a name already used by a user/room/team (e.g. 'general', an existing username); two admins renaming to the same free name simultaneously (check-then-set race between checkUsernameAvailability and Rooms.setNameById); a discussion/federation-unrelated path where slugified name equals a reserved handle.
Common situations: Renaming channels into well-known names ('support', 'admin') that exist as usernames; teams and channels competing for the same handle after a reorganization; bulk rename scripts not accounting for the shared namespace.
Related errors
- error-invalid-room
- error-not-allowed
- There must be a parent room to create a discussion.
- User not subscribed to room
- roomId was not provided.
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/934d6679a422d588.
Report an issue: GitHub.