CherryHQ/cherry-studio · error · Error
Message text cannot be empty.
Error message
Message text cannot be empty.
What it means
Thrown by WeixinBot.sendText() as a hard precondition guard before forwarding text to the WeChat send-message API. The WeChat protocol rejects empty messages server-side, so this check fails fast with a clear message rather than waiting for a round-trip API rejection. This is a private method invoked from reply() and send().
Source
Thrown at src/main/ai/channels/adapters/wechat/WeChatProtocol.ts:941
logger.info('Long-poll loop stopped')
}
private async ensureCredentials(): Promise<Credentials> {
if (this.credentials) return this.credentials
const stored = await loadCredentials(this.tokenPath!)
if (stored) {
this.credentials = stored
this.baseUrl = normalizeBaseUrl(stored.baseUrl)
return stored
}
return this.login()
}
private async sendText(userId: string, text: string, contextToken: string): Promise<void> {
if (text.length === 0) {
throw new Error('Message text cannot be empty.')
}
const credentials = await this.ensureCredentials()
await apiSendMessage(this.baseUrl, credentials.token, this.uin, buildTextMessage(userId, contextToken, text))
}
private async dispatchMessage(message: IncomingMessage): Promise<void> {
if (this.handlers.length === 0) return
const results = await Promise.allSettled(this.handlers.map(async (handler) => handler(message)))
for (const result of results) {
if (result.status === 'rejected') {
this.reportError(result.reason)
}
}
}
private rememberContext(message: WeixinMessage): void {View on GitHub (pinned to 726446b54c)
Solutions
- Check the text content before calling reply/send — if the LLM produced an empty response, skip the send or substitute a fallback message.
- Trace upstream: inspect sanitizeChannelOutput and any content-stripping transform to confirm it is not over-aggressively removing all content.
- If the empty string is legitimate (e.g., a 'typing' placeholder), reconsider the control flow — sendTyping/sendStopTyping exist for that purpose.
Example fix
// before
await this.bot.reply(message, text)
// after
if (text.trim().length === 0) {
logger.warn('Skipping empty reply', { userId: message.userId })
return
}
await this.bot.reply(message, text) Defensive patterns
Strategy: validation
Validate before calling
// Validate text before sending
function isValidMessageText(text: string): boolean {
return typeof text === 'string' && text.length > 0
}
if (!isValidMessageText(text)) {
logger.warn('Skipping send — message text is empty', { userId })
return
} Type guard
function isNonEmptyString(value: unknown): value is string {
return typeof value === 'string' && value.length > 0
} Prevention
- Check text.trim().length > 0 before calling reply() or send().
- Inspect sanitizeChannelOutput to ensure it does not strip all content from legitimate responses.
- Handle empty LLM completions upstream — substitute a fallback message or retry the generation.
When it happens
Trigger: Called from WeixinBot.reply(message, text) (line 739) or WeixinBot.send(userId, text) (line 771) when the text argument is an empty string. The upstream caller is typically a channel adapter that renders an LLM response — if the model produced an empty completion or all content was stripped during sanitization, the empty string reaches sendText.
Common situations: An LLM completion returned only whitespace or content that was entirely filtered by sanitizeChannelOutput; a message-templating bug produced an empty string; a streaming reply flushed with an empty buffer after all chunks were consumed by an earlier transform.
Related errors
- WeChat can only forward image files, not "${file.media_type}
- Invalid credentials format in ${tokenPath}
- Failed to upload image to WeChat CDN
- Not a regular file: ${displayPath}
- File exceeds the ${MAX_FILE_SIZE_BYTES} byte limit (${snapsh
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/9001ad5ad88139a8.
Report an issue: GitHub.