{"record":{"id":"f90b23e336e1b292","repo":"chenhg5/cc-connect","slug":"telegram-sendaudio-sendvoice-w","errorCode":null,"errorMessage":"telegram: SendAudio: sendVoice: %w","messagePattern":"telegram: SendAudio: sendVoice: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/telegram/telegram.go","lineNumber":1223,"sourceCode":"\t\tsendData = converted\n\t\tsendFormat = \"opus\"\n\t}\n\n\tif err := p.sendVoice(ctx, rc, sendData, sendFormat); err != nil {\n\t\tif sendFormat == \"mp3\" || sendFormat == \"m4a\" {\n\t\t\tif fallbackErr := p.sendAudio(ctx, rc, sendData, sendFormat); fallbackErr == nil {\n\t\t\t\treturn nil\n\t\t\t} else {\n\t\t\t\treturn fmt.Errorf(\n\t\t\t\t\t\"telegram: SendAudio: %w\",\n\t\t\t\t\terrors.Join(\n\t\t\t\t\t\tfmt.Errorf(\"sendVoice failed: %w\", err),\n\t\t\t\t\t\tfmt.Errorf(\"sendAudio fallback failed: %w\", fallbackErr),\n\t\t\t\t\t),\n\t\t\t\t)\n\t\t\t}\n\t\t}\n\t\treturn fmt.Errorf(\"telegram: SendAudio: sendVoice: %w\", err)\n\t}\n\treturn nil\n}\n\nfunc (p *Platform) sendVoice(ctx context.Context, rc replyContext, audio []byte, format string) error {\n\tbot, err := p.connectedBot(\"send voice\")\n\tif err != nil {\n\t\treturn err\n\t}\n\tparams := &tgbot.SendVoiceParams{\n\t\tChatID:          rc.chatID,\n\t\tMessageThreadID: rc.threadID,\n\t\tVoice:           &models.InputFileUpload{Filename: \"tts_audio.\" + telegramAudioFileExt(format), Data: bytes.NewReader(audio)},\n\t}\n\tif _, err := bot.SendVoice(ctx, params); err != nil {\n\t\treturn err\n\t}\n\treturn nil","sourceCodeStart":1205,"sourceCodeEnd":1241,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/telegram/telegram.go#L1205-L1241","documentation":"Returned when p.sendVoice fails and there is no audio fallback path taken (the fallback only runs when sendFormat/sendData support it). It wraps the raw sendVoice error under the 'telegram: SendAudio: sendVoice:' prefix, so the failure is entirely in the Bot API sendVoice call.","triggerScenarios":"The audio-sending method calls p.sendVoice, which returns err (Bot API error, connection failure, invalid parameters), and the code path skips the sendAudio fallback, returning fmt.Errorf(\"telegram: SendAudio: sendVoice: %w\", err).","commonSituations":"Voice payload not OGG/Opus ('Unsupported content type'); file_id referencing a deleted file; chat_write_denied in groups; network timeout to Telegram servers.","solutions":["Inspect the wrapped error for the Bot API description string and act on it directly.","Ensure the audio bytes are OGG with Opus codec — this is the only format sendVoice accepts reliably.","Verify bot membership/send permission in the target chat.","Add retry with backoff for 5xx/network errors; surface 429 retry_after to the caller."],"exampleFix":"// before\nreturn fmt.Errorf(\"telegram: SendAudio: sendVoice: %w\", err)\n// after: detect retryable Bot API errors\nvar apiErr *tgbot.Error\nif errors.As(err, &apiErr) && apiErr.RetryAfter > 0 { time.Sleep(...) }","handlingStrategy":"retry","validationCode":"if !strings.HasSuffix(strings.ToLower(filename), \".ogg\") { /* convert to ogg/opus first */ }","typeGuard":null,"tryCatchPattern":"err := p.sendVoice(ctx, rc, data, format)\nif err != nil {\n    if isTransient(err) { return retryWithBackoff(send) }\n    return fmt.Errorf(\"telegram: SendAudio: sendVoice: %w\", err)\n}","preventionTips":["Only send OGG/Opus via sendVoice","Handle Bot API 429/5xx with retries","Verify file_ids are still valid before reuse","Surface the wrapped Bot API description to logs"],"tags":["telegram","bot-api","voice-message","network"],"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"}