{"record":{"id":"921c01038ef96fa8","repo":"chenhg5/cc-connect","slug":"weixin-convert-s-to-amr-w","errorCode":null,"errorMessage":"weixin: convert %s to AMR: %w","messagePattern":"weixin: convert (.+?) to AMR: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"platform/weixin/media_outbound.go","lineNumber":266,"sourceCode":"func (p *Platform) SendAudio(ctx context.Context, replyCtx any, audio []byte, format string) error {\n\trc, err := p.resolveReplyContext(replyCtx)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif len(audio) == 0 {\n\t\treturn fmt.Errorf(\"weixin: empty audio\")\n\t}\n\n\t// Convert to AMR format if not already AMR\n\tsendData := audio\n\tsendFormat := strings.ToLower(strings.TrimSpace(format))\n\tif sendFormat == \"\" {\n\t\tsendFormat = \"wav\" // TTS typically outputs WAV\n\t}\n\tif sendFormat != \"amr\" {\n\t\tconverted, err := core.ConvertAudioToAMR(ctx, audio, sendFormat)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"weixin: convert %s to AMR: %w\", sendFormat, err)\n\t\t}\n\t\tsendData = converted\n\t\tsendFormat = \"amr\"\n\t}\n\n\tslog.Debug(\"weixin: audio converted\", \"format\", sendFormat, \"size\", len(sendData))\n\n\t// Upload to CDN as file type (voice uses same CDN upload mechanism)\n\tref, err := p.uploadToWeixinCDN(ctx, rc.peerUserID, sendData, uploadMediaFile, \"SendAudio\")\n\tif err != nil {\n\t\treturn err\n\t}\n\n\t// Send as voice message\n\titem := messageItem{\n\t\tType: messageItemVoice,\n\t\tVoiceItem: &voiceItem{\n\t\t\tMedia: &cdnMedia{","sourceCodeStart":248,"sourceCodeEnd":284,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/platform/weixin/media_outbound.go#L248-L284","documentation":"SendAudio in the weixin platform wraps the AMR conversion failure. WeChat (weixin) only accepts AMR audio, so any TTS-produced audio in another format (default WAV) is first run through core.ConvertAudioToAMR; if the underlying ffmpeg conversion fails, the error is wrapped and returned with the source format named.","triggerScenarios":"SendAudio is called with audio data whose format is not AMR and core.ConvertAudioToAMR fails — typically because ffmpeg is not installed, the input bytes are not valid WAV/MP3 audio, or the conversion subprocess errors/times out.","commonSituations":"Deployed container/host lacks ffmpeg; a text-to-speech backend returned an empty or truncated payload; the audio is declared as one format but actually contains different bytes; AMR encoder not available in the ffmpeg build.","solutions":["Install ffmpeg with AMR encoder support (libopencore-amrnb) on the host","Verify the incoming audio bytes actually match sendFormat (play/ffprobe the file)","Check the wrapped inner error for the exact ffmpeg failure reason","If the source is already AMR, ensure sendFormat is set to \"amr\" so conversion is skipped"],"exampleFix":"// before\nconverted, err := core.ConvertAudioToAMR(ctx, audio, sendFormat)\nif err != nil {\n    return fmt.Errorf(\"weixin: convert %s to AMR: %w\", sendFormat, err)\n}\n// after\nif len(audio) == 0 {\n    return fmt.Errorf(\"weixin: empty %s audio before AMR conversion\", sendFormat)\n}\nconverted, err := core.ConvertAudioToAMR(ctx, audio, sendFormat)\nif err != nil {\n    return fmt.Errorf(\"weixin: convert %s to AMR: %w\", sendFormat, err)\n}","handlingStrategy":"try-catch","validationCode":"if _, err := exec.LookPath(\"ffmpeg\"); err != nil {\n    return fmt.Errorf(\"ffmpeg required for AMR conversion\")\n}\nif len(audio) == 0 {\n    return fmt.Errorf(\"empty audio payload\")\n}","typeGuard":null,"tryCatchPattern":"converted, err := platform.SendAudio(ctx, audio, format)\nif err != nil && strings.Contains(err.Error(), \"convert\") {\n    log.Warn(\"AMR conversion failed; notify user audio undeliverable\", \"err\", err)\n}","preventionTips":["Install ffmpeg (with libopencore-amrnb) in every deployment image","Validate audio bytes/format before calling SendAudio","Prefer already-AMR sources to skip conversion","Surface conversion failures in health checks"],"tags":["go","audio","ffmpeg","weixin"],"backgroundTag":"missing-optional-dependency","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"}