{"record":{"id":"571ee707f8a0f5c7","repo":"hcengineering/platform","slug":"person-not-found","errorCode":null,"errorMessage":"Person not found","messagePattern":"Person not found","errorType":"http","errorClass":"ApiError","httpStatus":404,"severity":"error","filePath":"services/telegram-bot/pod-telegram-bot/src/server.ts","lineNumber":119,"sourceCode":"      if (req.body == null || typeof req.body !== 'object') {\n        throw new ApiError(400)\n      }\n\n      const { code } = req.body\n\n      if (code == null || code === '' || typeof code !== 'string') {\n        throw new ApiError(400)\n      }\n\n      const integration = await getAnyIntegrationByAccount(token.account)\n\n      if (integration !== undefined) {\n        throw new ApiError(409, 'User already authorized')\n      }\n\n      const person = await getAccountPerson(token.account)\n      if (person === undefined) {\n        throw new ApiError(404, 'Person not found')\n      }\n\n      const newRecord = await worker.authorizeUser(code, token.account, token.workspace)\n      if (newRecord === undefined) {\n        throw new ApiError(500)\n      }\n\n      void worker.limiter.add(newRecord.telegramId, async () => {\n        ctx.info('Connected account', { account: token.account, username: newRecord.username })\n        const message = await translate(telegram.string.AccountConnectedHtml, {\n          app: config.App,\n          name: `${person.firstName} ${person.lastName}`\n        })\n        await bot.telegram.sendMessage(newRecord.telegramId, message, { parse_mode: 'HTML' })\n      })\n\n      res.status(200)\n      res.json({})","sourceCodeStart":101,"sourceCodeEnd":137,"githubUrl":"https://github.com/hcengineering/platform/blob/63e28dc96483967b2fc21c881b3f1023c1de7718/services/telegram-bot/pod-telegram-bot/src/server.ts#L101-L137","documentation":"ApiError(404, 'Person not found') is thrown when getAccountPerson(token.account) returns undefined during the telegram-bot token exchange. The account is authenticated but no Person record is associated with it in the workspace, so the flow cannot proceed and the server responds with HTTP 404.","triggerScenarios":"The exchanging token's account exists but has no linked Person document in the target workspace (token.workspace), e.g. the account was created without person assignment or the person record was deleted.","commonSituations":"Service/guest accounts created outside the normal signup flow, workspaces where person records were removed or not synced, or a token issued for an account in a different workspace than where the person lives.","solutions":["Verify the account has a corresponding Person record in the target workspace and create/assign one if missing.","Check that token.account and token.workspace are consistent — the token may have been issued for the wrong workspace.","Re-run the account provisioning/onboarding step that links account to person, then retry authorization.","Change the response to a client-actionable error explaining that the account profile must be completed first."],"exampleFix":"// before\nconst person = await getAccountPerson(token.account)\nif (person === undefined) {\n  throw new ApiError(404, 'Person not found')\n}\n// after\nlet person = await getAccountPerson(token.account)\nif (person === undefined) {\n  person = await ensurePersonForAccount(token.account, token.workspace)\n}","handlingStrategy":"validation","validationCode":"const person = await getAccountPerson(account)\nif (person === undefined) {\n  throw new Error('Account has no linked Person; complete profile setup before connecting Telegram')\n}","typeGuard":"function isPersonNotFound(err: unknown): err is ApiError {\n  return err instanceof ApiError && (err as ApiError).message === 'Person not found'\n}","tryCatchPattern":"try {\n  await exchangeToken(token, code)\n} catch (err) {\n  if (err instanceof ApiError && err.message === 'Person not found') {\n    redirectToProfileSetup()\n  } else throw err\n}","preventionTips":["Ensure account signup always creates/links a Person record.","Verify the token's workspace matches the account's workspace.","Prevent deletion of Person records that still have linked accounts."],"tags":["http-404","missing-record","account-linking"],"backgroundTag":"missing-person-record","analyzedSha":"63e28dc96483967b2fc21c881b3f1023c1de7718","analyzedAt":"2026-08-29T15:21:27.377Z","schemaVersion":2},"datasetVersion":"2026-08-29T17:17:51.833Z"}