RocketChat/Rocket.Chat · error · Meteor.Error
error-token-does-not-exists
error-token-does-not-exists
Error message
Token does not exist
What it means
removePersonalAccessTokenOfUser first resolves the token by name via Users.findPersonalAccessTokenByTokenNameAndUserId({ userId, tokenName }); if no token with that name exists for the user, it throws error-token-does-not-exists before modifying loginTokens.
Solutions
- Treat it as success if the goal is 'token must not exist' — it is already gone.
- Otherwise verify the exact token name against the user's token list and retry.
- Guard re-runnable scripts so a missing token is not an error.
Example fix
// before
await Meteor.callAsync('personalAccessTokens:removeToken', { tokenName });
// after — idempotent delete
try {
await Meteor.callAsync('personalAccessTokens:removeToken', { tokenName });
} catch (e: any) {
if (e?.error !== 'error-token-does-not-exists') throw e; // already removed: fine
} Defensive patterns
Strategy: fallback
Validate before calling
const token = await Users.findPersonalAccessTokenByTokenNameAndUserId({ userId, tokenName });
if (!token) return; // goal already achieved: token absent Try / catch
try {
await Meteor.callAsync('personalAccessTokens:removeToken', { tokenName });
} catch (e: any) {
if (e?.error !== 'error-token-does-not-exists') throw e; // already gone — treat as success
} Prevention
- Make deletion flows idempotent: a missing token is the desired end state
- Debounce double-clicks on remove buttons
- In cleanup scripts, check existence first or swallow the not-exists error explicitly
When it happens
Trigger: Calling personalAccessTokens:removeToken for an already-removed token (double delete), a name that never existed, or a case-mismatched name.
Common situations: Idempotent-delete races in UIs (double-click), cleanup scripts re-running, tokens already rotated/removed elsewhere.
Understand the failure class
Background: "Not found" and "does not exist" errors: why "Task not found", "No such folder", and "Can't find" fire when a lookup comes back empty — this error's family across 14 libraries.
Related errors
- error-token-already-exists
- error-token-does-not-exists
- Banner not found
- Custom_User_Status_Error_Invalid_User_Status
- duplicated-account
AI-assisted analysis of RocketChat/Rocket.Chat@b2c16d5842 (2026-08-18).
Data as JSON: /api/errors/4cd06381d9ef462f.
Report an issue: GitHub.
Appendix: source
Thrown at apps/meteor/imports/personal-access-tokens/server/api/methods/removeToken.ts:25
declare module '@rocket.chat/ddp-client' {
// eslint-disable-next-line @typescript-eslint/naming-convention
interface ServerMethods {
'personalAccessTokens:removeToken'(params: { tokenName: string }): Promise<void>;
}
}
export const removePersonalAccessTokenOfUser = async (tokenName: string, userId: string): Promise<void> => {
if (!(await hasPermissionAsync(userId, 'create-personal-access-tokens'))) {
throw new Meteor.Error('not-authorized', 'Not Authorized', {
method: 'personalAccessTokens:removeToken',
});
}
const tokenExist = await Users.findPersonalAccessTokenByTokenNameAndUserId({
userId,
tokenName,
});
if (!tokenExist) {
throw new Meteor.Error('error-token-does-not-exists', 'Token does not exist', {
method: 'personalAccessTokens:removeToken',
});
}
await Users.removePersonalAccessTokenOfUser({
userId,
loginTokenObject: {
type: 'personalAccessToken',
name: tokenName,
},
});
};
Meteor.methods<ServerMethods>({
'personalAccessTokens:removeToken': twoFactorRequired(async function ({ tokenName }: { tokenName: string }) {
const uid = Meteor.userId();
if (!uid) {
throw new Meteor.Error('not-authorized', 'Not Authorized', {
method: 'personalAccessTokens:removeToken',View on GitHub (pinned to b2c16d5842)