{"record":{"id":"5fefffba4426b6f0","repo":"overleaf/overleaf","slug":"invalid-data","errorCode":null,"errorMessage":"invalid data","messagePattern":"invalid data","errorType":"exception","errorClass":"NotFoundError","httpStatus":404,"severity":"error","filePath":"services/web/app/src/Features/User/UserEmailsConfirmationHandler.mjs","lineNumber":51,"sourceCode":"    confirmCodeExpiresTimestamp,\n  }\n}\n\nasync function confirmEmailFromToken(req, token) {\n  const { data } = await OneTimeTokenHandler.promises.peekValueFromToken(\n    TOKEN_USE,\n    token\n  )\n  if (!data) {\n    throw new Errors.NotFoundError('no token found')\n  }\n\n  const loggedInUserId = SessionManager.getLoggedInUserId(req.session)\n  // user_id may be stored as an ObjectId or string\n  const userId = data.user_id?.toString()\n  const email = data.email\n  if (!userId || email !== EmailHelper.parseEmail(email)) {\n    throw new Errors.NotFoundError('invalid data')\n  }\n  if (loggedInUserId !== userId) {\n    throw new Errors.ForbiddenError('logged in user does not match token user')\n  }\n  const user = await UserGetter.promises.getUser(userId, { emails: 1 })\n  if (!user) {\n    throw new Errors.NotFoundError('user not found')\n  }\n  const emailExists = user.emails.some(emailData => emailData.email === email)\n  if (!emailExists) {\n    throw new Errors.NotFoundError('email missing for user')\n  }\n\n  await OneTimeTokenHandler.promises.expireToken(TOKEN_USE, token)\n  await UserUpdater.promises.confirmEmail(userId, email)\n\n  return { userId, email }\n}","sourceCodeStart":33,"sourceCodeEnd":69,"githubUrl":"https://github.com/overleaf/overleaf/blob/28ad3b03b71cb4311decdcb55c36b33ec10d72db/services/web/app/src/Features/User/UserEmailsConfirmationHandler.mjs#L33-L69","documentation":"NotFoundError('invalid data') is thrown by confirmEmailFromToken when the token's payload lacks a usable user_id or the embedded email does not match its own normalized parse (email !== EmailHelper.parseEmail(email)). This is a sanity check on the token's stored data before any session or DB work. It indicates a corrupted or forged/malformed token payload.","triggerScenarios":"peekValueFromToken returned data but data.user_id is null/undefined, or data.email is malformed/ambiguous so it fails the self-consistency check email === parseEmail(email).","commonSituations":"Hand-crafted or tampered token values; old tokens written by a previous schema version storing fields under different names; email stored with mixed case/whitespace by an older send path.","solutions":["Re-issue the confirmation token via the normal sendConfirmationCode flow","Inspect what the current sendConfirmationCode writes into the token payload and confirm field names (user_id, email)","Check for version drift: tokens created before an upgrade may have a different payload shape — invalidate them","Ensure emails are normalized (parseEmail) at token-creation time, not just at confirmation time"],"exampleFix":"// before\n// token payload stored under different keys in old version\nawait OneTimeTokenHandler.promises.setValueFromToken(TOKEN_USE, token, { uid: userId, mail: email })\n// after\nawait OneTimeTokenHandler.promises.setValueFromToken(TOKEN_USE, token, {\n  user_id: userId.toString(),\n  email: EmailHelper.parseEmail(email),\n})","handlingStrategy":"validation","validationCode":"if (!tokenData?.user_id?.toString() || tokenData.email !== EmailHelper.parseEmail(tokenData.email)) {\n  throw new Error('token payload invalid')\n}","typeGuard":"function hasValidTokenData(data) {\n  return Boolean(data && data.user_id && data.email && data.email === EmailHelper.parseEmail(data.email))\n}","tryCatchPattern":"try {\n  await UserEmailsConfirmationHandler.promises.confirmEmailFromToken(req, token)\n} catch (err) {\n  if (err instanceof Errors.NotFoundError && err.message === 'invalid data') { /* issue fresh token */ }\n  else throw err\n}","preventionTips":["Normalize emails with EmailHelper.parseEmail when writing token payloads","Invalidate old-format tokens after schema changes","Never hand-construct confirmation tokens outside the official send path"],"tags":["tokens","validation","email-confirmation"],"backgroundTag":"invalid-token-payload","analyzedSha":"28ad3b03b71cb4311decdcb55c36b33ec10d72db","analyzedAt":"2026-09-03T02:10:22.807Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T07:17:11.731Z"}