{"record":{"id":"dfc85d18951b8770","repo":"chenhg5/cc-connect","slug":"telegram-sendaudio-w","errorCode":null,"errorMessage":"telegram: SendAudio: %w","messagePattern":"telegram: SendAudio: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/telegram/telegram.go","lineNumber":1214,"sourceCode":"\n\tswitch sendFormat {\n\tcase \"ogg\", \"opus\", \"mp3\", \"m4a\":\n\t\t// Attempt these formats directly with sendVoice first.\n\tdefault:\n\t\tconverted, err := telegramConvertAudioToOpus(ctx, audio, sendFormat)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"telegram: SendAudio: convert %s to opus: %w\", sendFormat, err)\n\t\t}\n\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}","sourceCodeStart":1196,"sourceCodeEnd":1232,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/telegram/telegram.go#L1196-L1232","documentation":"When both sendVoice and its sendAudio fallback fail for mp3/m4a audio, SendAudio returns a joined error \"telegram: SendAudio: \" containing \"sendVoice failed\" and \"sendAudio fallback failed\" via errors.Join. It means Telegram rejected the audio both as a voice note and as an audio document.","triggerScenarios":"sendVoice fails (Telegram rejects mp3/m4a as voice on old API paths, network error, flood limit) AND sendAudio also fails (upload error, chat access, size limit).","commonSituations":"Temporary Telegram API incidents; bot flood-limited so both attempts fail; corrupt mp3/m4a payloads; bot removed from chat between attempts; oversized audio buffers.","solutions":["Inspect both joined causes with errors.Is/As to see if it is 429, network, or an API rejection","Add retry-with-backoff around SendAudio; a single flood limit can fail both paths","Validate the mp3/m4a bytes decode correctly (e.g. ffprobe) before sending","Prefer ogg/opus output from TTS to avoid the fallback path entirely","Confirm bot membership and chat ID validity if both failures are chat-not-found"],"exampleFix":"// before\nerr := p.SendAudio(ctx, rc, audio, \"mp3\") // one-shot, both paths can fail\n// after\nvar retryErr error\nfor i := 0; i < 3; i++ {\n    if retryErr = p.SendAudio(ctx, rc, audio, \"mp3\"); retryErr == nil {\n        break\n    }\n    time.Sleep(time.Duration(1<<i) * time.Second)\n}","handlingStrategy":"retry","validationCode":"// validate mp3 header before sending\nif len(audio) < 3 || !bytes.Equal(audio[:3], []byte{'I','D','3'}) && audio[0] != 0xFF {\n    return errors.New(\"payload does not look like mp3/m4a audio\")\n}","typeGuard":null,"tryCatchPattern":"var joinErr *telegramSendAudioError // or inspect via errors.Is\nif err := p.SendAudio(ctx, rc, audio, \"mp3\"); err != nil {\n    if errors.Is(err, context.DeadlineExceeded) || isFlood(err) {\n        // exponential backoff retry\n    }\n    return err\n}","preventionTips":["Prefer ogg/opus TTS output to avoid the dual-failure path","Add exponential backoff around SendAudio","Verify audio bytes decode with ffprobe before sending","Check bot membership and rate limits when both voice and audio attempts fail"],"tags":["telegram","audio","fallback","api-error"],"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-14T00:17:10.932Z"}