{"record":{"id":"838b7faf8d0355a7","repo":"chenhg5/cc-connect","slug":"qwen-tts-read-response-w","errorCode":null,"errorMessage":"qwen tts: read response: %w","messagePattern":"qwen tts: read response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/tts.go","lineNumber":154,"sourceCode":"\t\treturn nil, \"\", fmt.Errorf(\"qwen tts: marshal request: %w\", err)\n\t}\n\n\treq, err := http.NewRequestWithContext(ctx, http.MethodPost, q.BaseURL, bytes.NewReader(jsonData))\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"qwen tts: create request: %w\", err)\n\t}\n\treq.Header.Set(\"Authorization\", \"Bearer \"+q.APIKey)\n\treq.Header.Set(\"Content-Type\", \"application/json\")\n\n\tresp, err := q.Client.Do(req)\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"qwen tts: request: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"qwen tts: read response: %w\", err)\n\t}\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, \"\", fmt.Errorf(\"qwen tts API %d: %s\", resp.StatusCode, body)\n\t}\n\n\tvar result struct {\n\t\tCode    string `json:\"code\"`\n\t\tMessage string `json:\"message\"`\n\t\tOutput  struct {\n\t\t\tAudio struct {\n\t\t\t\tURL string `json:\"url\"`\n\t\t\t} `json:\"audio\"`\n\t\t} `json:\"output\"`\n\t}\n\tif err := json.Unmarshal(body, &result); err != nil {\n\t\treturn nil, \"\", fmt.Errorf(\"qwen tts: parse response: %w\", err)\n\t}\n\tif result.Code != \"\" {","sourceCodeStart":136,"sourceCodeEnd":172,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/tts.go#L136-L172","documentation":"After a successful HTTP exchange, Synthesize reads the entire response body with io.ReadAll. A read failure (connection reset mid-body, truncated chunked transfer, context cancelled during read) is wrapped as 'qwen tts: read response'. The status check happens only after this read succeeds.","triggerScenarios":"io.ReadAll(resp.Body) returns an error: server closed connection mid-response, network interruption during body transfer, or ctx cancelled while streaming the body.","commonSituations":"Flaky mobile/VPN connection dropping mid-download; API gateway timing out and cutting the response; very slow network combined with a caller context deadline.","solutions":["Retry the request — this is typically transient.","Check the wrapped error: net errors like unexpected EOF/reset indicate network instability.","Increase the caller's context deadline if large responses are expected.","Check any LB/proxy idle timeouts between client and API."],"exampleFix":"// before\nbody, err := io.ReadAll(resp.Body)\nif err != nil { return nil, \"\", err } // give up\n// after\nbody, err := io.ReadAll(resp.Body)\nif err != nil {\n    if isRetryable(err) { return synthesizeWithRetry(ctx, text, opts) }\n    return nil, \"\", fmt.Errorf(\"qwen tts: read response: %w\", err)\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"audio, _, err := q.Synthesize(ctx, text, opts)\nif err != nil && strings.Contains(err.Error(), \"read response\") {\n    if ne, ok := err.(net.Error); ok && ne.Timeout() {\n        return retryWithLongerDeadline(ctx, text, opts)\n    }\n    return fmt.Errorf(\"connection dropped during TTS response: %w\", err)\n}","preventionTips":["Always retry once on mid-body read failures; they are usually transient.","Avoid very short context deadlines for large synthesis payloads.","Check LB/proxy idle-timeout settings between client and API.","Prefer stable networks for long-running agent sessions (warn on VPN/mobile)."],"tags":["tts","qwen","network","io"],"backgroundTag":"network-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"}