CherryHQ/cherry-studio · error · Error
Telegram bot token is required
Error message
Telegram bot token is required
What it means
Thrown by TelegramAdapter.performConnect() when this.botToken is falsy at connect time. The token is read from config.channelConfig.bot_token in the constructor (TelegramAdapter.ts:50) and never mutated, so this fires only when the channel was configured with an empty/missing token. checkReady() at line 55 returns false for the same condition, so a well-behaved caller gating on readiness should never reach the throw — this is a defensive guard for a caller that skips readiness.
Source
Thrown at src/main/ai/channels/adapters/telegram/TelegramAdapter.ts:61
// never hit the cap. Instead reset only after the bot has polled cleanly for this window —
// so transient failures spread over the adapter's lifetime don't monotonically exhaust it.
private readonly stabilityResetMs = 60_000
constructor(config: ChannelAdapterConfig<'telegram'>) {
super(config)
const { bot_token, allowed_chat_ids } = config.channelConfig
this.botToken = bot_token
this.allowedChatIds = allowed_chat_ids ?? []
this.notifyChatIds = [...this.allowedChatIds]
}
protected override async checkReady(): Promise<boolean> {
return !!this.botToken
}
protected override async performConnect(_signal: AbortSignal): Promise<void> {
if (!this.botToken) {
throw new Error('Telegram bot token is required')
}
this.shouldStop = false
this.reconnectAttempts = 0
await this.startBot()
}
private async startBot(): Promise<void> {
const bot = new Bot(this.botToken)
this.bot = bot
// Auth middleware — must be first
bot.use(async (ctx, next) => {
const chatId = ctx.chat?.id?.toString()
if (this.allowedChatIds.length > 0 && (!chatId || !this.allowedChatIds.includes(chatId))) {
this.log.debug('Dropping message from unauthorized chat', { chatId })
return
}
await next()View on GitHub (pinned to 726446b54c)
Solutions
- Ensure the Telegram channel config has a non-empty bot_token before calling connect — the checkReady() guard exists for exactly this (TelegramAdapter.ts:55).
- In the UI, mark the bot token field required and disable the connect action until filled.
- Validate bot_token format at config-write time: Telegram tokens match /^\d{9,10}:[A-Za-z0-9_-]{35}$.
- If migrating, backfill bot_token from the legacy config store before enabling the channel.
Example fix
// before — connect proceeds, then throws an opaque error
await adapter.connect(signal)
// after — gate on readiness to avoid the throw entirely
if (await adapter.checkReady()) {
await adapter.connect(signal)
} else {
showConfigError('Telegram bot token is required')
} Defensive patterns
Strategy: validation
Validate before calling
// Validate the Telegram bot token BEFORE constructing/connecting the adapter.
// Telegram token format: <bot_id>:<auth_token>, e.g. 123456789:ABCdef...
const TELEGRAM_TOKEN_RE = /^\d{8,10}:[A-Za-z0-9_-]{30,40}$/
function isValidTelegramToken(v: unknown): v is string {
return typeof v === 'string' && TELEGRAM_TOKEN_RE.test(v)
}
// At channel-enable time:
if (!isValidTelegramToken(config.channelConfig.bot_token)) {
return { ok: false, field: 'bot_token', reason: 'Telegram bot token is required (format: <id>:<secret>)' }
}
await telegramAdapter.connect(signal) Type guard
function hasTelegramBotToken(config: unknown): config is { bot_token: string } {
return (
typeof config === 'object' && config !== null &&
typeof (config as { bot_token?: unknown }).bot_token === 'string' &&
(config as { bot_token: string }).bot_token.length > 0
)
} Try / catch
// This throw is best prevented, not caught — it indicates a misconfigured channel.
// If you must catch, treat it as a permanent config error (do not retry):
try {
await adapter.connect(signal)
} catch (e) {
if (e instanceof Error && e.message === 'Telegram bot token is required') {
markChannelConfigInvalid(channelId, 'bot_token', 'Enter a Telegram bot token from @BotFather')
return // do not retry — config must change
}
throw e
} Prevention
- Make the bot_token field required in the channel config UI and disable Connect until it is filled.
- Validate the Telegram token regex at config-write time so malformed tokens never persist.
- Use checkReady() (TelegramAdapter.ts:55) as the connect gate — it returns false for missing tokens.
- Obtain the token from @BotFather on Telegram; never hand-edit it.
When it happens
Trigger: performConnect() is invoked while bot_token in the channel config is empty string, null, or undefined. The checkReady() guard returns false on the same condition, so this throw fires only when the adapter is connected without a readiness check (e.g. a code path that calls connect() unconditionally, or a race where config was cleared between checkReady and performConnect).
Common situations: The user created a Telegram channel in agent settings but never pasted a bot token; the config store was reset/corrupted; a migration left bot_token empty; the UI allowed enabling the channel without validating the token field.
Related errors
- Private key must be a non-empty string
- Cherry Assistant package definition is unavailable
- Cherry Assistant package configuration is invalid: ${invalid
- QQ Bot AppID and ClientSecret are required
- Slack bot token (xoxb-...) is required
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/dd9debe7bd6c56fc.
Report an issue: GitHub.