{"record":{"id":"ce659995d1b3f6ae","repo":"RocketChat/Rocket.Chat","slug":"error-invalid-token-ce6599","errorCode":null,"errorMessage":"error-invalid-token","messagePattern":"error-invalid-token","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/meteor/server/lib/users/verifyEmail.ts","lineNumber":6,"sourceCode":"import type { IUser } from '@rocket.chat/core-typings';\nimport { Users } from '@rocket.chat/models';\n\nexport async function verifyEmail(user: Pick<IUser, '_id' | 'services' | 'emails'>, token: string): Promise<boolean> {\n\tif (user.services?.email?.verificationTokens?.length === 0) {\n\t\tthrow new Error('error-invalid-token');\n\t}\n\n\tconst tokenRecord = await user.services?.email?.verificationTokens?.find((t) => t.token === token);\n\tif (!tokenRecord) {\n\t\tthrow new Error('error-invalid-token');\n\t}\n\n\tconst emailsRecord = user.emails?.find((e) => e.address === tokenRecord.address);\n\n\tif (!emailsRecord) {\n\t\tthrow new Error('error-invalid-token');\n\t}\n\n\tconst result = await Users.verifyEmailByAddress(user._id, tokenRecord.address);\n\tif (result.modifiedCount === 0) {\n\t\tthrow new Error('error-invalid-token');\n\t}\n","sourceCodeStart":1,"sourceCodeEnd":24,"githubUrl":"https://github.com/RocketChat/Rocket.Chat/blob/b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0/apps/meteor/server/lib/users/verifyEmail.ts#L1-L24","documentation":"verifyEmail throws a plain Error('error-invalid-token') — not a Meteor.Error — at four sites. At line 5-7 the guard is user.services?.email?.verificationTokens?.length === 0: the account has an empty token array, so no verification token was ever issued and any supplied token is meaningless. Quirk: if verificationTokens is undefined (property missing), this guard passes and the failure surfaces at the next one instead.","triggerScenarios":"Calling verifyEmail for a user created without verification tokens: admin-created accounts, OAuth-provisioned accounts, users created before Accounts_EmailVerification was enabled, or tokens cleared by a later flow.","commonSituations":"Custom registration pipelines that skip Accounts.sendVerificationEmail; tests with hand-built user fixtures that have services.email but no verificationTokens array; migrations dropping nested services fields.","solutions":["Mint a fresh token first: call Accounts.sendVerificationEmail(userId) and verify with the new link","In tests, populate the fixture: services.email.verificationTokens = [{ token, address, when }]","If users are provisioned programmatically, add token issuance to the provisioning script"],"exampleFix":"// before\nawait verifyEmail(user, token); // user has verificationTokens: [] -> error-invalid-token\n\n// after\nawait Accounts.sendVerificationEmail(user._id);\nconst fresh = await Users.findOneById(user._id);\nconst newToken = fresh.services.email.verificationTokens.at(-1).token;\nawait verifyEmail(fresh, newToken);","handlingStrategy":"validation","validationCode":"const tokens = user.services?.email?.verificationTokens;\nif (!tokens || tokens.length === 0) {\n  // no token to verify against: trigger a resend instead of calling verifyEmail\n}","typeGuard":"const hasVerificationTokens = (u: Pick<IUser, 'services'>): boolean =>\n  Array.isArray(u.services?.email?.verificationTokens) && u.services!.email!.verificationTokens.length > 0;","tryCatchPattern":"try {\n  await verifyEmail(user, token);\n} catch (error) {\n  if ((error as Error).message === 'error-invalid-token') {\n    // note: plain Error, not Meteor.Error — check .message, not .error\n  } else {\n    throw error;\n  }\n}","preventionTips":["Ensure Accounts.sendVerificationEmail runs in your registration pipeline","Test fixtures must include a populated verificationTokens array","Check token existence before calling verifyEmail — the function gives no detail about which of its four guards fired"],"tags":["email-verification","token","meteor","users"],"backgroundTag":"email-verification-token-invalid","analyzedSha":"b2c16d5842cbe6b69b59bdf6fc5e5f1afcd1f0b0","analyzedAt":"2026-08-18T15:26:39.429Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}