chenhg5/cc-connect · error

telegram: send: %w

Error message

telegram: send: %w

What it means

The Telegram platform's Reply method wraps any error returned by the underlying bot API sendMessage call with the prefix "telegram: send: ". It indicates the message (as HTML) could not be delivered to Telegram. The original transport/API error is preserved via %w for errors.Is/As inspection.

Source

Thrown at platform/telegram/telegram.go:1079

			slog.Warn("telegram: HTML rejected by Telegram, sending as plain text",
				"method", "Reply",
				"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 by splitting and sending as multiple messages
			slog.Warn("telegram: message too long, splitting into chunks",
				"method", "Reply",
				"html_len", len(html),
			)
			return p.sendChunked(ctx, bot, rc, html)
		}
		if err != nil {
			return fmt.Errorf("telegram: send: %w", err)
		}
	}
	return nil
}

// Send sends a new message (not a reply)
func (p *Platform) Send(ctx context.Context, rctx any, content string) error {
	rc, ok := rctx.(replyContext)
	if !ok {
		return fmt.Errorf("telegram: invalid reply context type %T", rctx)
	}
	bot, err := p.connectedBot("send")
	if err != nil {
		return err
	}

	html := core.MarkdownToSimpleHTML(content)
	params := &tgbot.SendMessageParams{

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Check the wrapped cause with errors.Unwrap / errors.As to see whether it is network, auth, or a Telegram API error
  2. Verify the bot is a member of the target chat and the chatID in replyContext is correct
  3. Ensure the bot token is valid (run cc-connect doctor or call getMe)
  4. Retry with backoff on 429 responses; Telegram rate limits bots per chat
  5. Pre-check HTML length so oversized messages go through sendChunked instead of a single sendMessage

Example fix

// before
err := p.Reply(ctx, rctx, hugeMessage) // single sendMessage fails
// after
if len(html) > 4000 {
    return p.sendChunked(ctx, bot, rc, html)
}
Defensive patterns

Strategy: retry

Validate before calling

// check message length before sending
if len([]rune(html)) > 4096 {
    return p.sendChunked(ctx, bot, rc, html)
}

Try / catch

if err := p.Reply(ctx, rc, html); err != nil {
    var apiErr *tgbot.Error
    if errors.As(err, &apiErr) && apiErr.ResponseCode == 429 {
        // wait retry-after and retry
    }
    return fmt.Errorf("telegram reply failed: %w", err)
}

Prevention

When it happens

Trigger: Calling Platform.Reply with a replyContext whose chat is unreachable: bot.SendMessage returns a network error, Telegram API error (chat not found, bot blocked, message too long if chunking path not taken), or rate limit.

Common situations: Bot kicked from or never added to the chat; wrong chat_id in the reply context; Telegram API downtime or local network failure; hitting the 4096-char limit when the html_len pre-check did not route to sendChunked; flood limits from many rapid replies.

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


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/ce5885ae65ba6d8f. Report an issue: GitHub.