overleaf/overleaf · error · NotFoundError

invalid data

Error message

invalid data

What it means

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.

Source

Thrown at services/web/app/src/Features/User/UserEmailsConfirmationHandler.mjs:51

    confirmCodeExpiresTimestamp,
  }
}

async function confirmEmailFromToken(req, token) {
  const { data } = await OneTimeTokenHandler.promises.peekValueFromToken(
    TOKEN_USE,
    token
  )
  if (!data) {
    throw new Errors.NotFoundError('no token found')
  }

  const loggedInUserId = SessionManager.getLoggedInUserId(req.session)
  // user_id may be stored as an ObjectId or string
  const userId = data.user_id?.toString()
  const email = data.email
  if (!userId || email !== EmailHelper.parseEmail(email)) {
    throw new Errors.NotFoundError('invalid data')
  }
  if (loggedInUserId !== userId) {
    throw new Errors.ForbiddenError('logged in user does not match token user')
  }
  const user = await UserGetter.promises.getUser(userId, { emails: 1 })
  if (!user) {
    throw new Errors.NotFoundError('user not found')
  }
  const emailExists = user.emails.some(emailData => emailData.email === email)
  if (!emailExists) {
    throw new Errors.NotFoundError('email missing for user')
  }

  await OneTimeTokenHandler.promises.expireToken(TOKEN_USE, token)
  await UserUpdater.promises.confirmEmail(userId, email)

  return { userId, email }
}

View on GitHub (pinned to 28ad3b03b7)

Solutions

  1. Re-issue the confirmation token via the normal sendConfirmationCode flow
  2. Inspect what the current sendConfirmationCode writes into the token payload and confirm field names (user_id, email)
  3. Check for version drift: tokens created before an upgrade may have a different payload shape — invalidate them
  4. Ensure emails are normalized (parseEmail) at token-creation time, not just at confirmation time

Example fix

// before
// token payload stored under different keys in old version
await OneTimeTokenHandler.promises.setValueFromToken(TOKEN_USE, token, { uid: userId, mail: email })
// after
await OneTimeTokenHandler.promises.setValueFromToken(TOKEN_USE, token, {
  user_id: userId.toString(),
  email: EmailHelper.parseEmail(email),
})
Defensive patterns

Strategy: validation

Validate before calling

if (!tokenData?.user_id?.toString() || tokenData.email !== EmailHelper.parseEmail(tokenData.email)) {
  throw new Error('token payload invalid')
}

Type guard

function hasValidTokenData(data) {
  return Boolean(data && data.user_id && data.email && data.email === EmailHelper.parseEmail(data.email))
}

Try / catch

try {
  await UserEmailsConfirmationHandler.promises.confirmEmailFromToken(req, token)
} catch (err) {
  if (err instanceof Errors.NotFoundError && err.message === 'invalid data') { /* issue fresh token */ }
  else throw err
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of overleaf/overleaf@28ad3b03b7 (2026-09-03). Data as JSON: /api/errors/5fefffba4426b6f0. Report an issue: GitHub.