{"record":{"id":"21da907b5de11270","repo":"chenhg5/cc-connect","slug":"qwen-tts-read-audio-w","errorCode":null,"errorMessage":"qwen tts: read audio: %w","messagePattern":"qwen tts: read audio: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/tts.go","lineNumber":192,"sourceCode":"\t}\n\tif result.Output.Audio.URL == \"\" {\n\t\treturn nil, \"\", fmt.Errorf(\"qwen tts: empty audio URL in response\")\n\t}\n\n\t// Download WAV from temporary URL\n\taudioReq, err := http.NewRequestWithContext(ctx, http.MethodGet, result.Output.Audio.URL, nil)\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"qwen tts: create download request: %w\", err)\n\t}\n\taudioResp, err := q.Client.Do(audioReq)\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"qwen tts: download audio: %w\", err)\n\t}\n\tdefer audioResp.Body.Close()\n\n\twavData, err := io.ReadAll(audioResp.Body)\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"qwen tts: read audio: %w\", err)\n\t}\n\treturn wavData, \"wav\", nil\n}\n\n// ──────────────────────────────────────────────────────────────\n// OpenAITTS — OpenAI-compatible TTS implementation (P1)\n// ──────────────────────────────────────────────────────────────\n\n// OpenAITTS implements TextToSpeech using the OpenAI /v1/audio/speech API.\ntype OpenAITTS struct {\n\tAPIKey  string\n\tBaseURL string\n\tModel   string\n\tClient  *http.Client\n}\n\n// NewOpenAITTS creates a new OpenAITTS instance.\nfunc NewOpenAITTS(apiKey, baseURL, model string, client *http.Client) *OpenAITTS {","sourceCodeStart":174,"sourceCodeEnd":210,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/tts.go#L174-L210","documentation":"After the WAV download response is received (core/tts.go:192), QwenTTS.Synthesize reads the whole body with io.ReadAll. This error wraps a failure while streaming the response body — the connection dropped, the server closed mid-transfer, or a body-limited reader hit its cap.","triggerScenarios":"Connection reset while reading the audio bytes, server-side abort/timeout mid-stream, context cancellation firing during the read, or a Body limited by http.MaxBytesReader that exceeded its limit.","commonSituations":"Large audio files over flaky mobile/office networks, an intermediate proxy terminating long transfers, or surrounding code cancelling ctx partway through synthesis.","solutions":["Retry Synthesize; transient body-read interruptions are usually temporary","Verify the ctx is not cancelled mid-operation and that no middleware limits the response body size","Increase the client timeout and check proxy idle/connection limits","Wrap the body reader with retry/resume logic if downloads are routinely large"],"exampleFix":"// before\nwavData, err := io.ReadAll(audioResp.Body)\nif err != nil {\n    return nil, \"\", fmt.Errorf(\"qwen tts: read audio: %w\", err)\n}\n// after\nwavData, err := io.ReadAll(audioResp.Body)\nif err != nil {\n    return nil, \"\", fmt.Errorf(\"qwen tts: read audio (%d bytes read): %w\", len(wavData), err)\n}\nif audioResp.StatusCode != http.StatusOK {\n    return nil, \"\", fmt.Errorf(\"qwen tts: audio download HTTP %d\", audioResp.StatusCode)\n}","handlingStrategy":"retry","validationCode":"// Enforce a sane response size cap before parsing:\nconst maxWAV = 20 << 20 // 20 MiB\nlimited := io.LimitReader(audioResp.Body, maxWAV+1)","typeGuard":null,"tryCatchPattern":"wav, format, err := tts.Synthesize(ctx, text, opts)\nif err != nil && strings.Contains(err.Error(), \"read audio\") {\n    // transient stream failure — retry once, then degrade gracefully\n    if wav, format, err = tts.Synthesize(ctx, text, opts); err != nil {\n        return fmt.Errorf(\"tts unavailable: %w\", err)\n    }\n}","preventionTips":["Avoid cancelling the context mid-synthesis; scope ctx to the whole Synthesize call","Increase client timeout for large texts producing long audio","Route downloads through stable network paths, not flaky proxies"],"tags":["tts","network","io","http","qwen"],"backgroundTag":"file-read-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"}