RocketChat/Rocket.Chat · error · MeteorError

error-field-unavailable

error-field-unavailable

Error message

${escape(userData.username)} is already in use :(

What it means

Thrown by validateUserData() on CREATE when checkUsernameAvailability() returns false for the submitted username. Availability is not just uniqueness: the shared helper (server/lib/users/checkUsernameAvailability.ts) also runs it against reserved words and external-directory collisions via the checkUsernameAvailabilityCallback, so some 'available-looking' names are still blocked. Code is error-field-unavailable and the message echoes the escaped username.

Source

Thrown at apps/meteor/server/lib/users/saveUser/validateUserData.ts:95

	if (userData.username && !nameValidation.test(userData.username)) {
		throw new MeteorError('error-input-is-not-a-valid-field', `${escape(userData.username)} is not a valid username`, {
			method: 'insertOrUpdateUser',
			input: userData.username,
			field: 'Username',
		});
	}

	if (!isUpdateUserData(userData) && !userData.password && !userData.setRandomPassword) {
		throw new MeteorError('error-the-field-is-required', 'The field Password is required', {
			method: 'insertOrUpdateUser',
			field: 'Password',
		});
	}

	if (!isUpdateUserData(userData)) {
		if (userData.username && !(await checkUsernameAvailability(userData.username))) {
			throw new MeteorError('error-field-unavailable', `${escape(userData.username)} is already in use :(`, {
				method: 'insertOrUpdateUser',
				field: userData.username,
			});
		}

		if (userData.email && !(await checkEmailAvailability(userData.email))) {
			throw new MeteorError('error-field-unavailable', `${escape(userData.email)} is already in use :(`, {
				method: 'insertOrUpdateUser',
				field: userData.email,
			});
		}
	}
});

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Check first with the dedicated endpoint: GET /api/v1/users.checkUsernameAvailability?username=... (api/v1/users.ts:1228) and only proceed when it returns true.
  2. On 409/unavailable, fetch a suggestion via GET /api/v1/users.getUsernameSuggestion (api/v1/users.ts:1177) and either use it or surface it to the user.
  3. For imports, de-duplicate against GET /api/v1/users.list before submitting, and suffix colliding names deterministically.

Example fix

// before
await POST '/api/v1/users.create', { username: 'alice', email: 'a1@b.c', password: 'pw' }); // throws 'already in use'

// after
const ok = await GET `/api/v1/users.checkUsernameAvailability?username=alice`;
const username = ok.available ? 'alice' : (await GET '/api/v1/users.getUsernameSuggestion?username=alice').result;
await POST '/api/v1/users.create', { username, email: 'a1@b.c', password: 'pw' });
Defensive patterns

Strategy: validation

Validate before calling

const { result: available } = await GET `/api/v1/users.checkUsernameAvailability?username=${encodeURIComponent(u)}`;
if (!available) {
  const { result: suggestion } = await GET `/api/v1/users.getUsernameSuggestion?username=${encodeURIComponent(u)}`;
  payload.username = suggestion;
}

Type guard

null

Try / catch

catch (e) {
  if (e.error === 'error-field-unavailable' && e.details?.field === u) {
    // fetch a suggestion and resubmit once
  }
}

Prevention

When it happens

Trigger: users.create with a username already owned by another user, matched case-insensitively; a username on the reserved list (e.g. 'admin' variants) even though no user holds it; collisions with an LDAP/external user cache entry.

Common situations: Bulk import colliding with existing accounts; retrying a create after a partial success; test scripts reusing a fixed username; usernames differing only in case or trailing punctuation being normalized to an existing one.

Related errors


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