RocketChat/Rocket.Chat · error · Meteor.Error

error-token-already-exists

error-token-already-exists

Error message

A token with this name already exists

What it means

Personal access token names are unique per user. generatePersonalAccessTokenOfUser first looks up Users.findPersonalAccessTokenByTokenNameAndUserId({ userId, tokenName }); if a token with that name already exists for the user it aborts with error-token-already-exists before creating a new secret.

Solutions

  1. Choose a different, unique tokenName for the new token.
  2. If you want a new secret under the existing name, call personalAccessTokens:regenerateToken instead.
  3. Or remove the old token first with personalAccessTokens:removeToken, then generate.

Example fix

// before
await Meteor.callAsync('personalAccessTokens:generateToken', { tokenName: 'ci-deploy', bypassTwoFactor: false });

// after — name already used: rotate the secret instead
await Meteor.callAsync('personalAccessTokens:regenerateToken', { tokenName: 'ci-deploy' });
Defensive patterns

Strategy: validation

Validate before calling

const existing = await Users.findPersonalAccessTokenByTokenNameAndUserId({ userId, tokenName });
if (existing) {
	// rotate instead: call personalAccessTokens:regenerateToken
}

Try / catch

try {
	await Meteor.callAsync('personalAccessTokens:generateToken', { tokenName, bypassTwoFactor: false });
} catch (e: any) {
	if (e?.error === 'error-token-already-exists') {
		await Meteor.callAsync('personalAccessTokens:regenerateToken', { tokenName }); // desired behavior: rotate
	} else throw e;
}

Prevention

When it happens

Trigger: Calling personalAccessTokens:generateToken with a tokenName the same user already used — double-submitted create form, retry after a network failure, or simply forgetting an earlier token.

Common situations: CI scripts hard-coding a token name on every run, UI double-click on 'Add', rotating tokens by re-creating instead of regenerating.

Related errors


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

Appendix: source

Thrown at apps/meteor/imports/personal-access-tokens/server/api/methods/generateToken.ts:37

	userId,
}: {
	tokenName: string;
	userId: string;
	bypassTwoFactor: boolean;
}): Promise<string> => {
	if (!(await hasPermissionAsync(userId, 'create-personal-access-tokens'))) {
		throw new Meteor.Error('not-authorized', 'Not Authorized', {
			method: 'personalAccessTokens:generateToken',
		});
	}

	const token = Random.secret();
	const tokenExist = await Users.findPersonalAccessTokenByTokenNameAndUserId({
		userId,
		tokenName,
	});
	if (tokenExist) {
		throw new Meteor.Error('error-token-already-exists', 'A token with this name already exists', {
			method: 'personalAccessTokens:generateToken',
		});
	}

	await Users.addPersonalAccessTokenToUser({
		userId,
		loginTokenObject: {
			hashedToken: Accounts._hashLoginToken(token),
			type: 'personalAccessToken',
			createdAt: new Date(),
			lastTokenPart: token.slice(-6),
			name: tokenName,
			bypassTwoFactor,
		},
	});
	return token;
};

View on GitHub (pinned to b2c16d5842)