CherryHQ/cherry-studio · error · Error
Bot is not connected
Error message
Bot is not connected
What it means
Thrown by WeChatAdapter.sendMessage() when this.bot (a WeixinBot instance) is null. The bot is set in performConnect() (WeChatAdapter.ts:46) and nulled in performDisconnect() (line 82). WeChat login is a multi-step QR flow that can take many seconds, so the window where sendMessage is called before connect completes is larger than for the other adapters. After disconnect, this.bot is null and sends fail with this message.
Source
Thrown at src/main/ai/channels/adapters/wechat/WeChatAdapter.ts:91
}
})
this.log.info('WeChat bot started')
}
protected override async performDisconnect(): Promise<void> {
if (this.bot) {
this.bot.stop()
this.bot = null
this.sendQrToRenderer('', 'disconnected')
this.log.info('WeChat bot stopped')
}
}
// oxlint-disable-next-line no-unused-vars -- abstract method signature
async sendMessage(chatId: string, text: string, _opts?: SendMessageOptions): Promise<void> {
if (!this.bot) {
throw new Error('Bot is not connected')
}
const chunks = splitMessage(text, WECHAT_MAX_LENGTH)
for (let i = 0; i < chunks.length; i++) {
await this.bot.send(chatId, chunks[i])
if (i < chunks.length - 1) {
await new Promise((resolve) => setTimeout(resolve, 100))
}
}
}
override async sendFile(chatId: string, file: FileAttachment): Promise<void> {
if (!this.bot) {
throw new Error('Bot is not connected')
}
// The reverse-engineered WeChat protocol only supports outbound images todayView on GitHub (pinned to 726446b54c)
Solutions
- Gate outbound sends on the adapter connected state, and specifically on WeChat login completion (markConnected is called at WeChatAdapter.ts:64 only after credentials are obtained).
- Queue messages while the channel is in QR-pending or reconnecting state and flush on markConnected.
- Have performDisconnect await/drain pending sends before nulling this.bot.
- Subscribe callers to channel-state events so they stop sending on disconnect.
Example fix
// before — races with the long WeChat QR login
await wechatAdapter.sendMessage(chatId, text)
// after — check the connected flag set only after login
if (!wechatAdapter.isConnected()) {
await pendingWeChatSends.enqueue({ chatId, text })
return
}
await wechatAdapter.sendMessage(chatId, text) Defensive patterns
Strategy: validation
Validate before calling
// WeChat login is slow and interactive; check the connected state (set only after
// markConnected at WeChatAdapter.ts:64) and queue while in QR-pending or reconnecting.
if (!wechatAdapter.isConnected()) {
await pendingWeChatSends.enqueue({ chatId, text })
return
}
await wechatAdapter.sendMessage(chatId, text) Type guard
// WeChat login completion is signaled by markConnected — use the base class flag
function isWeChatReadyToSend(adapter: ChannelAdapter): boolean {
return adapter.isConnected()
} Try / catch
try {
await wechatAdapter.sendMessage(chatId, text)
} catch (e) {
if (e instanceof Error && e.message === 'Bot is not connected') {
// WeChat disconnects are often session-expiry re-logins; queue and retry
await pendingWeChatSends.enqueue({ chatId, text })
return
}
throw e
} Prevention
- Treat the WeChat channel as 'not connected' until the QR scan completes — markConnected fires only after credentials are obtained (WeChatAdapter.ts:64).
- Queue outbound messages during QR-pending and session-expiry re-login; flush on reconnect.
- Drain pending sends in performDisconnect before nulling this.bot.
- For WeChat, also handle the case where this.bot is set but session-expired (runLoop re-login) — gate on a finer 'logged in' flag.
When it happens
Trigger: sendMessage() called before performConnect() finished the QR login flow (bot is assigned at line 46 before login completes, but a connect failure leaves it null); or after performDisconnect() nulled it. Because WeChat requires an interactive QR scan, the adapter can sit in a 'pending QR' state for a long time during which this.bot may be set but not yet logged in — sending in that window fails downstream rather than here.
Common situations: A scheduled notification fires while the WeChat channel is waiting for QR scan (user has not scanned yet); the WeChat session expired and runLoop() is re-authenticating (login flow blocks the loop); the user disconnected the channel and a queued send drained after teardown.
Related errors
- Bot is not connected
- Login cancelled
- Client is not connected
- QR login confirmed, but the API did not return bot credentia
- QR login failed after ${MAX_QR_RETRIES} expired QR codes. Us
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/6dc7fd76b057fa75.
Report an issue: GitHub.