hcengineering/platform · error · ApiError
Person not found
Error message
Person not found
What it means
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.
Source
Thrown at services/telegram-bot/pod-telegram-bot/src/server.ts:119
if (req.body == null || typeof req.body !== 'object') {
throw new ApiError(400)
}
const { code } = req.body
if (code == null || code === '' || typeof code !== 'string') {
throw new ApiError(400)
}
const integration = await getAnyIntegrationByAccount(token.account)
if (integration !== undefined) {
throw new ApiError(409, 'User already authorized')
}
const person = await getAccountPerson(token.account)
if (person === undefined) {
throw new ApiError(404, 'Person not found')
}
const newRecord = await worker.authorizeUser(code, token.account, token.workspace)
if (newRecord === undefined) {
throw new ApiError(500)
}
void worker.limiter.add(newRecord.telegramId, async () => {
ctx.info('Connected account', { account: token.account, username: newRecord.username })
const message = await translate(telegram.string.AccountConnectedHtml, {
app: config.App,
name: `${person.firstName} ${person.lastName}`
})
await bot.telegram.sendMessage(newRecord.telegramId, message, { parse_mode: 'HTML' })
})
res.status(200)
res.json({})View on GitHub (pinned to 63e28dc964)
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.
Example fix
// before
const person = await getAccountPerson(token.account)
if (person === undefined) {
throw new ApiError(404, 'Person not found')
}
// after
let person = await getAccountPerson(token.account)
if (person === undefined) {
person = await ensurePersonForAccount(token.account, token.workspace)
} Defensive patterns
Strategy: validation
Validate before calling
const person = await getAccountPerson(account)
if (person === undefined) {
throw new Error('Account has no linked Person; complete profile setup before connecting Telegram')
} Type guard
function isPersonNotFound(err: unknown): err is ApiError {
return err instanceof ApiError && (err as ApiError).message === 'Person not found'
} Try / catch
try {
await exchangeToken(token, code)
} catch (err) {
if (err instanceof ApiError && err.message === 'Person not found') {
redirectToProfileSetup()
} else throw err
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- platform.status.ResourceNotFound
- Target workspace not found or not accessible
- File ${file} not found
- Document not found
- Couldn't find contact by id + channel.attachedTo
AI-assisted analysis of hcengineering/platform@63e28dc964 (2026-08-29).
Data as JSON: /api/errors/571ee707f8a0f5c7.
Report an issue: GitHub.