chenhg5/cc-connect · error
telegram: sendWithButtons: %w
Error message
telegram: sendWithButtons: %w
What it means
This wraps an error from the actual Telegram Bot API message-send performed inside SendWithButtons, after the HTML body was rendered and chunking was not needed. It indicates the sendMessage call with an inline keyboard failed — the reply context type was valid, but delivery failed.
Source
Thrown at platform/telegram/telegram.go:1322
slog.Warn("telegram: HTML rejected by Telegram, sending as plain text",
"method", "SendWithButtons",
"error", errMsg,
"html_prefix", truncateForLog(html, 200),
"html_len", len(html),
)
params.Text = content
params.ParseMode = ""
_, err = bot.SendMessage(ctx, params)
} else if strings.Contains(errMsg, "message is too long") {
// Handle message too long: first chunk with buttons, rest without
slog.Warn("telegram: message too long, splitting into chunks",
"method", "SendWithButtons",
"html_len", len(html),
)
return p.sendChunkedWithButtons(ctx, bot, rc, html, rows)
}
if err != nil {
return fmt.Errorf("telegram: sendWithButtons: %w", err)
}
}
return nil
}
// DeletePreviewMessage deletes a stale preview message so the caller can send a fresh one.
func (p *Platform) DeletePreviewMessage(ctx context.Context, previewHandle any) error {
h, ok := previewHandle.(*telegramPreviewHandle)
if !ok {
return fmt.Errorf("telegram: invalid preview handle type %T", previewHandle)
}
bot, err := p.connectedBot("delete preview")
if err != nil {
return err
}
_, err = bot.DeleteMessage(ctx, &tgbot.DeleteMessageParams{ChatID: h.chatID, MessageID: h.messageID})
if err != nil {
slog.Debug("telegram: delete preview message failed", "error", err)View on GitHub (pinned to 4000b2338a)
Solutions
- Read the wrapped error for the Bot API description; fix the specific violation (button callback data ≤64 bytes, valid HTML entities).
- Ensure user content is HTML-escaped before rendering so entity parsing cannot fail.
- Fall back to sendChunkedWithButtons when len(html) exceeds limits — the code already does this above; verify thresholds.
- Retry with backoff on 429/5xx responses.
Example fix
// before
html := fmt.Sprintf("<b>%s</b>", userText)
// after: escape to avoid 'can't parse entities'
html := "<b>" + html.EscapeString(userText) + "</b>" Defensive patterns
Strategy: try-catch
Validate before calling
if len(content) > 4096 { /* use chunked send */ }
for _, row := range buttons { for _, b := range row { if len(b.CallbackData) > 64 { return errors.New("callback data too long") } } } Try / catch
if err := p.sendWithButtons(ctx, bot, rc, html, rows); err != nil {
if strings.Contains(err.Error(), "can't parse entities") { /* escape HTML and retry */ }
return fmt.Errorf("telegram: sendWithButtons: %w", err)
} Prevention
- HTML-escape all user content before sending
- Keep button callback data ≤64 bytes
- Chunk messages longer than 4096 characters
- Retry on 429 with the server-provided delay
When it happens
Trigger: p.sendWithButtons (or the Bot API call inside it) returns err after the chunking branch: e.g. sendMessage rejects the markup, the text, or the network request fails.
Common situations: Inline keyboard rows exceeding Telegram limits (too many buttons/bad callback data >64 bytes); markdown/HTML parse error ('can't parse entities'); message text >4096 chars without chunking; network or 429 rate-limit errors.
Understand the failure class
Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.
Related errors
- sendVoice failed: %w
- sendAudio fallback failed: %w
- telegram: SendAudio: sendVoice: %w
- get file: %w
- get file: empty file_path returned for file_id %s
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/a4b66b65d2cdcfbb.
Report an issue: GitHub.