hcengineering/platform · error · PlatformError

platform.status.AccountNotFound

platform.status.AccountNotFound

Error message

AccountNotFound

What it means

createAccessLink decodes an access token and looks up the account UUID it embeds via db.account.findOne. If no account row matches that UUID, the platform throws AccountNotFound. This means the token references an account that no longer exists (or never existed) in the database.

Source

Thrown at server/account/src/operations.ts:766

  params: {
    role: AccountRole
    firstName?: string
    lastName?: string
    extra?: string
    navigateUrl?: string
    spaces?: string[]

    notBefore?: number
    expiration?: number
    personalized?: boolean
  }
): Promise<string> {
  const { role, firstName, lastName, navigateUrl, spaces, notBefore, expiration, personalized = true } = params
  const { account, workspace: workspaceUuid, extra } = decodeTokenVerbose(ctx, token)

  const currentAccount = await db.account.findOne({ uuid: account })
  if (currentAccount == null) {
    throw new PlatformError(new Status(Severity.ERROR, platform.status.AccountNotFound, { account }))
  }

  if (workspaceUuid == null) {
    throw new PlatformError(new Status(Severity.ERROR, platform.status.BadRequest, {}))
  }

  const workspace = await db.workspace.findOne({ uuid: workspaceUuid })
  if (workspace == null) {
    throw new PlatformError(new Status(Severity.ERROR, platform.status.WorkspaceNotFound, { workspaceUuid }))
  }

  let extraObj: Record<string, string> | undefined

  if (params.extra != null) {
    try {
      extraObj = JSON.parse(params.extra)
    } catch (e) {
      ctx.error("Invalid extra parameter, couldn't parse JSON", { extra: params.extra })

View on GitHub (pinned to 63e28dc964)

Solutions

  1. Re-authenticate so the user gets a token minted against the current database.
  2. Verify the token was issued for the same environment/database you are calling (check transactor URL and DB name).
  3. Confirm the account row still exists: query db.account.findOne({ uuid: <account from token> }).
  4. If accounts are being deleted, invalidate/revoke outstanding tokens on deletion to avoid stale-token calls.

Example fix

// before: reusing an old token after DB reset
const link = await client.createAccessLink(token, params)
// after: re-login to obtain a token for the current DB
const token = await login(email, password)
const link = await client.createAccessLink(token, params)
Defensive patterns

Strategy: try-catch

Validate before calling

const payload = decodeJwt(token)
if (payload?.account == null) throw new Error('token missing account claim')

Type guard

function hasAccountClaim(t: unknown): t is { account: string } {
  return typeof t === 'object' && t !== null && typeof (t as any).account === 'string'
}

Try / catch

try {
  const link = await createAccessLink(token, params)
} catch (err) {
  if (isPlatformError(err, platform.status.AccountNotFound)) {
    await reauthenticate() // token references a deleted/foreign account
  } else throw err
}

Prevention

When it happens

Trigger: Calling createAccessLink with a token whose embedded `account` UUID is absent from db.account — e.g. the account was deleted after the token was issued, the token was minted for a different/staging database, or the token is forged/corrupted.

Common situations: Pointing a client at a fresh or restored database while reusing old tokens; account cleanup jobs deleting accounts with live tokens; copying tokens between environments (dev/prod); typos when manually crafting tokens in tests.

Related errors


AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29). Data as JSON: /api/errors/c4f066d859aaa756. Report an issue: GitHub.