RocketChat/Rocket.Chat · error · Meteor.Error

error-could-not-save-identity

error-could-not-save-identity

Error message

Could not save user identity

What it means

saveUser throws error-could-not-save-identity (method 'saveUser') when saveUserIdentity returns false while applying username/name changes. False means: the target user vanished, the new username failed validateName, or _setUsername could not assign it (unavailable or blocked). saveUser aggregates all these into one error, so the underlying cause must be inferred.

Source

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

		options?.auditStore?.setOriginalUser(oldUserData);

		await validateUserEditing(userId, userData);

		// update user
		const updater = Users.getUpdater();

		if (userData.hasOwnProperty('username') || userData.hasOwnProperty('name')) {
			if (
				!(await saveUserIdentity({
					_id: userData._id,
					username: userData.username,
					name: userData.name,
					updateUsernameInBackground: true,
					updater,
					session,
				}))
			) {
				throw new Meteor.Error('error-could-not-save-identity', 'Could not save user identity', {
					method: 'saveUser',
				});
			}
		}

		if (typeof userData.statusText === 'string') {
			await setStatusText(oldUserData, userData.statusText, { updater, session });
		}

		if (userData.email) {
			const shouldSendVerificationEmailToUser = userData.verified !== true;
			await setEmail(userData._id, userData.email, shouldSendVerificationEmailToUser, userData.verified === true, updater);
		}

		if (
			userData.password?.trim() &&
			(await hasPermissionAsync(userId, 'edit-other-user-password')) &&
			passwordPolicy.validate(userData.password)

View on GitHub (pinned to b2c16d5842)

Solutions

  1. Pre-check availability with checkUsernameAvailability(newUsername) before calling saveUser
  2. Verify the new username passes the format rules (validateName) and is not in the blocked list
  3. If it still fails, check whether the target user still exists and inspect server logs from _setUsername for the precise refusal

Example fix

// before
await saveUser(actorId, { _id: targetId, username: 'taken.name' });

// after
const available = await checkUsernameAvailability('taken.name');
if (!available) throw new Error('Username already in use');
await saveUser(actorId, { _id: targetId, username: 'taken.name' });
Defensive patterns

Strategy: validation

Validate before calling

if (userData.username) {
  const available = await checkUsernameAvailability(userData.username);
  if (!available) throw new Error('Username already in use');
}
await saveUser(actorId, userData);

Type guard

const isIdentitySaveError = (e: unknown): boolean =>
  typeof e === 'object' && e !== null && (e as { error?: unknown }).error === 'error-could-not-save-identity';

Try / catch

try {
  await saveUser(actorId, userData);
} catch (e) {
  if (isIdentitySaveError(e)) {
    // aggregated cause: username taken, invalid format, or user deleted — check each in order
    await diagnoseIdentitySave(userData);
  }
}

Prevention

When it happens

Trigger: Renaming a user to an already-taken or reserved username through the admin user editor (saveUser with username set); a username with invalid characters; concurrent deletion of the target during the save.

Common situations: Admin UI rename colliding with an existing username (including case-insensitive matches); import jobs assigning names that hit the blocked list; identity sync (SAML/OAuth) pushing a name change that fails validation.

Related errors


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