{"record":{"id":"06738ea776ec8793","repo":"chenhg5/cc-connect","slug":"telegram-send-chunk-d-w","errorCode":null,"errorMessage":"telegram: send chunk %d: %w","messagePattern":"telegram: send chunk (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/telegram/telegram.go","lineNumber":1545,"sourceCode":"func (p *Platform) sendChunked(ctx context.Context, bot telegramBot, rc replyContext, html string) error {\n\tchunks := core.SplitMessageCodeFenceAware(html, telegramMaxMessageLen)\n\tfor i, chunk := range chunks {\n\t\tparams := &tgbot.SendMessageParams{\n\t\t\tChatID:          rc.chatID,\n\t\t\tMessageThreadID: rc.threadID,\n\t\t\tText:            chunk,\n\t\t\tParseMode:       models.ParseModeHTML,\n\t\t}\n\t\tif i == 0 && rc.messageID != 0 {\n\t\t\tparams.ReplyParameters = &models.ReplyParameters{MessageID: rc.messageID}\n\t\t}\n\t\tif _, err := bot.SendMessage(ctx, params); err != nil {\n\t\t\t// If HTML fails, try plain text\n\t\t\tif strings.Contains(err.Error(), \"can't parse\") {\n\t\t\t\tparams.Text = chunk\n\t\t\t\tparams.ParseMode = \"\"\n\t\t\t\tif _, err2 := bot.SendMessage(ctx, params); err2 != nil {\n\t\t\t\t\treturn fmt.Errorf(\"telegram: send chunk %d: %w\", i, err2)\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\"telegram: send chunk %d: %w\", i, err)\n\t\t\t}\n\t\t}\n\t}\n\treturn nil\n}\n\n// sendChunkedWithButtons splits a message that's too long and sends it as multiple messages.\n// The first chunk includes the inline keyboard buttons.\nfunc (p *Platform) sendChunkedWithButtons(ctx context.Context, bot telegramBot, rc replyContext, html string, rows [][]models.InlineKeyboardButton) error {\n\tchunks := core.SplitMessageCodeFenceAware(html, telegramMaxMessageLen)\n\tfor i, chunk := range chunks {\n\t\tparams := &tgbot.SendMessageParams{\n\t\t\tChatID:          rc.chatID,\n\t\t\tMessageThreadID: rc.threadID,\n\t\t\tText:            chunk,","sourceCodeStart":1527,"sourceCodeEnd":1563,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/telegram/telegram.go#L1527-L1563","documentation":"In the chunked-send path (platform/telegram/telegram.go:1545), when an HTML-formatted SendMessage fails with a parse error, the code retries the same chunk as plain text; if the plain-text retry also fails, the error is wrapped as 'telegram: send chunk %d' with the chunk index. This means the chunk could not be delivered in either format.","triggerScenarios":"Calling the chunked send function where chunk i fails both HTML and plain-text delivery — chat inaccessible, bot blocked/kicked, message content rejected by Telegram (e.g. empty text), or network/API failure on both attempts.","commonSituations":"Long streaming responses split into chunks sent to a chat the bot just lost access to; Telegram rate limiting (429) hitting one chunk mid-sequence; a chunk that is only whitespace/unparseable entities rejected twice.","solutions":["Inspect the wrapped cause: 429 'Too Many Requests' → honor retry_after and resend the chunk","'chat not found' / 'Forbidden' → restore bot access before resuming the chunk sequence","Ensure no chunk is empty or only whitespace before sending","Add per-chunk retry with backoff before failing the whole message","Log the chunk index alongside the cause to locate the failing portion of the content"],"exampleFix":"// before\nif _, err2 := bot.SendMessage(ctx, params); err2 != nil {\n    return fmt.Errorf(\"telegram: send chunk %d: %w\", i, err2)\n}\n// after\nif _, err2 := bot.SendMessage(ctx, params); err2 != nil {\n    var apiErr *telegram.Error\n    if errors.As(err2, &apiErr) && apiErr.RetryAfter > 0 {\n        time.Sleep(time.Duration(apiErr.RetryAfter) * time.Second)\n        if _, err3 := bot.SendMessage(ctx, params); err3 == nil {\n            continue\n        }\n    }\n    return fmt.Errorf(\"telegram: send chunk %d: %w\", i, err2)\n}","handlingStrategy":"try-catch","validationCode":"chunk = strings.TrimSpace(chunk)\nif chunk == \"\" {\n    return nil // nothing to send\n}\nif len(chunk) > telegramMaxMessageLen {\n    return errors.New(\"chunk exceeds Telegram limit\")\n}","typeGuard":null,"tryCatchPattern":"err := sendChunks(ctx, bot, chunks)\nvar apiErr *telegram.Error\nif err != nil && errors.As(err, &apiErr) && apiErr.Code == 429 {\n    time.Sleep(time.Duration(apiErr.RetryAfter) * time.Second)\n    err = sendChunks(ctx, bot, chunks[i:]) // resume from failed chunk\n}","preventionTips":["Validate chunks (non-empty, within 4096 chars) before the send loop","Add small delays between chunks to avoid Telegram rate limits","Track the failing chunk index so retries resume rather than restart","Monitor bot membership; pause streams for chats where the bot was blocked"],"tags":["telegram","api","chunking","send-message","golang"],"backgroundTag":"api-request-failed","analyzedSha":"4000b2338aa6e850c99df54f8b0ed6ed7460b401","analyzedAt":"2026-09-06T11:45:09.575Z","contentChangedAt":"2026-09-06T11:45:09.575Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}