mastra-ai/mastra · error
Telegram getMe returned a non-bot user; expected a BotFather
Error message
Telegram getMe returned a non-bot user; expected a BotFather token
What it means
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.
Source
Thrown at channels/telegram/src/telegram-client.ts:76
*
* @see https://core.telegram.org/bots/api#getme
*/
export async function getMe(botToken: string, apiBaseUrl: string = TELEGRAM_API_BASE_URL): Promise<TelegramUser> {
let result: TelegramUser;
try {
result = await botApiRequest<TelegramUser>(botToken, 'getMe', apiBaseUrl);
} catch (cause) {
// A transport/timeout failure is a connectivity problem, not a token
// rejection — surface it as-is rather than mislabeling it as a bad token.
if (cause instanceof Error && (cause as { isTransportError?: boolean }).isTransportError) {
throw cause;
}
throw new Error(`Telegram rejected the bot token: ${cause instanceof Error ? cause.message : String(cause)}`, {
cause,
});
}
if (!result?.is_bot) {
throw new Error('Telegram getMe returned a non-bot user; expected a BotFather token');
}
return result;
}
/** Options for {@link setWebhook}. */
export interface SetWebhookOptions {
/** Public HTTPS URL Telegram will POST updates to. */
url: string;
/** Shared secret echoed back as `X-Telegram-Bot-Api-Secret-Token` on every POST. */
secretToken: string;
/** Update types to receive. Note: `message_reaction` must be listed explicitly. */
allowedUpdates?: string[];
/** Drop the backlog of updates queued while the bot was offline. */
dropPendingUpdates?: boolean;
}
/**
* Register a per-bot webhook. Setting a webhook disables `getUpdates`View on GitHub (pinned to 75dd419e61)
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
Example fix
// before
new TelegramProvider({ botToken: process.env.TELEGRAM_USER_TOKEN })
// after
new TelegramProvider({ botToken: process.env.TELEGRAM_BOT_TOKEN }) // token from @BotFather Defensive patterns
Strategy: validation
Validate before calling
async function assertBotToken(token: string, baseUrl = 'https://api.telegram.org') {
const res = await fetch(`${baseUrl}/bot${token}/getMe`);
const data: { ok: boolean; result?: { is_bot?: boolean } } = await res.json();
if (!data.ok || !data.result?.is_bot) throw new Error('Token is not a BotFather bot token');
} Type guard
function isBotUser(u: unknown): u is { id: number; is_bot: true; username: string } {
return typeof u === 'object' && u !== null && (u as any).is_bot === true;
} Try / catch
try {
await provider.connect(agentId, { botToken });
} catch (err) {
if (err instanceof Error && err.message.includes('non-bot user')) {
throw new Error('TELEGRAM_BOT_TOKEN is not a BotFather token — regenerate via @BotFather');
}
throw err;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Google Workspace Directory authentication is not configured.
- Telegram installation secrets are encrypted at rest, but no
- Telegram rejected the bot token: ${cause instanceof Error ?
- Agent "${agentId}" is already connected to Telegram. Disconn
- TelegramProvider needs a baseUrl to register a webhook. Set
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/0a253e0e79226c54.
Report an issue: GitHub.