mastra-ai/mastra · error
Telegram rejected the bot token: ${cause instanceof Error ?
Error message
Telegram rejected the bot token: ${cause instanceof Error ? cause.message : String(cause)} What it means
getMe() validates a bot token via Telegram's getMe endpoint and is the canonical 'is this token good?' check. If botApiRequest throws a non-transport error (i.e. Telegram rejected the request — usually HTTP 401 Unauthorized for a bad token), it is rethrown wrapped as 'Telegram rejected the bot token: <cause>'. Genuine transport failures (timeouts) are rethrown as-is to avoid mislabeling connectivity problems as bad tokens, and a non-bot user result has its own distinct error.
Source
Thrown at channels/telegram/src/telegram-client.ts:71
}
/**
* Validate a bot token via `getMe` and resolve the bot's identity. Throws if
* the token is rejected or the returned user is not a bot.
*
* @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. */View on GitHub (pinned to 75dd419e61)
Solutions
- Regenerate a token via @BotFather (/mybots > API Token) and update the stored/env value.
- Trim whitespace and verify the token format matches the BotFather-issued pattern (digits:alphanumeric).
- Confirm the value is a bot token from BotFather, not a user or app token.
- If the cause message is a timeout/network error (transport), fix connectivity — the wrapper preserves genuine transport errors unwrapped.
Example fix
// before
const client = createTelegramClient(process.env.TELEGRAM_BOT_TOKEN);
// after
const token = process.env.TELEGRAM_BOT_TOKEN?.trim();
if (!token || !/^\d+:[\w-]{30,}$/.test(token)) {
throw new Error('TELEGRAM_BOT_TOKEN is not a valid BotFather token');
}
const client = createTelegramClient(token); Defensive patterns
Strategy: validation
Validate before calling
const token = process.env.TELEGRAM_BOT_TOKEN?.trim();
if (!token || !/^\d+:[\w-]{30,}$/.test(token)) {
throw new Error('TELEGRAM_BOT_TOKEN missing or malformed (expected BotFather format)');
}
await getMe(token); // confirms validity with Telegram before use Try / catch
try {
await getMe(token);
} catch (e) {
const m = /Telegram rejected the bot token: (.+)/.exec(e.message);
if (m) {
console.error(`Bad bot token (${m[1]}); regenerate via @BotFather`);
} else throw e; // transport errors surface as-is
} Prevention
- Trim tokens read from env/files — stray newlines cause 401s.
- Only use BotFather-issued bot tokens; keep a startup getMe health check.
- Update stored tokens everywhere immediately after regenerating via BotFather.
When it happens
Trigger: Calling getMe()/me() — or any flow that validates a bot token (bot registration, install verification) — with an invalid, revoked, or mistyped BotFather token, causing getMe to fail with 401 Unauthorized.
Common situations: Typo when pasting the token from BotFather; token regenerated/revoked but the old value still in env/DB; using a user token (xoxp-like or a personal token) instead of a bot token; trailing whitespace/newline in the token env var.
Related errors
- Telegram getMe returned a non-bot user; expected a BotFather
- ${errorData.message || 'Invalid email or password'}
- Invalid email or password
- ${errorData.message || 'Failed to create account'}
- Failed to create account
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/9ad1bd0658a54fef.
Report an issue: GitHub.