{"record":{"id":"0a253e0e79226c54","repo":"mastra-ai/mastra","slug":"telegram-getme-returned-a-non-bot-user-expected-a","errorCode":null,"errorMessage":"Telegram getMe returned a non-bot user; expected a BotFather token","messagePattern":"Telegram getMe returned a non-bot user; expected a BotFather token","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"channels/telegram/src/telegram-client.ts","lineNumber":76,"sourceCode":" *\n * @see https://core.telegram.org/bots/api#getme\n */\nexport async function getMe(botToken: string, apiBaseUrl: string = TELEGRAM_API_BASE_URL): Promise<TelegramUser> {\n  let result: TelegramUser;\n  try {\n    result = await botApiRequest<TelegramUser>(botToken, 'getMe', apiBaseUrl);\n  } catch (cause) {\n    // A transport/timeout failure is a connectivity problem, not a token\n    // rejection — surface it as-is rather than mislabeling it as a bad token.\n    if (cause instanceof Error && (cause as { isTransportError?: boolean }).isTransportError) {\n      throw cause;\n    }\n    throw new Error(`Telegram rejected the bot token: ${cause instanceof Error ? cause.message : String(cause)}`, {\n      cause,\n    });\n  }\n  if (!result?.is_bot) {\n    throw new Error('Telegram getMe returned a non-bot user; expected a BotFather token');\n  }\n  return result;\n}\n\n/** Options for {@link setWebhook}. */\nexport interface SetWebhookOptions {\n  /** Public HTTPS URL Telegram will POST updates to. */\n  url: string;\n  /** Shared secret echoed back as `X-Telegram-Bot-Api-Secret-Token` on every POST. */\n  secretToken: string;\n  /** Update types to receive. Note: `message_reaction` must be listed explicitly. */\n  allowedUpdates?: string[];\n  /** Drop the backlog of updates queued while the bot was offline. */\n  dropPendingUpdates?: boolean;\n}\n\n/**\n * Register a per-bot webhook. Setting a webhook disables `getUpdates`","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/channels/telegram/src/telegram-client.ts#L58-L94","documentation":"After calling Telegram's getMe API with the supplied bot token, the response user object did not have is_bot set to true. The TelegramProvider requires a token created via BotFather; a valid-looking token that resolves to a normal user account cannot act as a bot. The library throws to fail fast before registering webhooks or polling.","triggerScenarios":"Calling TelegramProvider.connect() with a botToken that is actually a non-bot user token, or a corrupted/placeholder token that Telegram nevertheless authenticates but returns a user with is_bot=false.","commonSituations":"Pasting a user auth token instead of a BotFather token; token copied from the wrong bot or truncated/reformatted so Telegram resolves it incorrectly; testing with dummy tokens like '123:ABC' in dev.","solutions":["Create a bot with @BotFather via /newbot and use the issued token (it ends in a bot username and getMe returns is_bot: true)","Verify the token with a manual GET https://api.telegram.org/bot<token>/getMe and confirm the response contains \"is_bot\": true","Check for whitespace, quotes, or truncation in the env var holding the token (e.g. process.env.TELEGRAM_BOT_TOKEN)","Regenerate the token via BotFather /revoke if the old one was rotated or invalid"],"exampleFix":"// before\nnew TelegramProvider({ botToken: process.env.TELEGRAM_USER_TOKEN })\n// after\nnew TelegramProvider({ botToken: process.env.TELEGRAM_BOT_TOKEN }) // token from @BotFather","handlingStrategy":"validation","validationCode":"async function assertBotToken(token: string, baseUrl = 'https://api.telegram.org') {\n  const res = await fetch(`${baseUrl}/bot${token}/getMe`);\n  const data: { ok: boolean; result?: { is_bot?: boolean } } = await res.json();\n  if (!data.ok || !data.result?.is_bot) throw new Error('Token is not a BotFather bot token');\n}","typeGuard":"function isBotUser(u: unknown): u is { id: number; is_bot: true; username: string } {\n  return typeof u === 'object' && u !== null && (u as any).is_bot === true;\n}","tryCatchPattern":"try {\n  await provider.connect(agentId, { botToken });\n} catch (err) {\n  if (err instanceof Error && err.message.includes('non-bot user')) {\n    throw new Error('TELEGRAM_BOT_TOKEN is not a BotFather token — regenerate via @BotFather');\n  }\n  throw err;\n}","preventionTips":["Store the BotFather token in a dedicated env var and never reuse user tokens","Sanity-check tokens with a getMe call in CI or a startup health check","Watch for truncation/copy artifacts (quotes, whitespace) when pasting tokens","Rotate tokens via BotFather /revoke and update secrets in one place"],"tags":["telegram","authentication","configuration"],"backgroundTag":"invalid-bot-token","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}