{"record":{"id":"ae90138d1a5564bf","repo":"chenhg5/cc-connect","slug":"qwen-tts-parse-response-w","errorCode":null,"errorMessage":"qwen tts: parse response: %w","messagePattern":"qwen tts: parse response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/tts.go","lineNumber":170,"sourceCode":"\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 != \"\" {\n\t\treturn nil, \"\", fmt.Errorf(\"qwen tts API error %s: %s\", result.Code, result.Message)\n\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()","sourceCodeStart":152,"sourceCodeEnd":188,"githubUrl":"https://github.com/chenhg5/cc-connect/blob/4000b2338aa6e850c99df54f8b0ed6ed7460b401/core/tts.go#L152-L188","documentation":"After a 200 status, Synthesize unmarshals the JSON body into the result struct (code/message/output.audio.url). If the body is not valid JSON or doesn't match the expected shape, it returns 'qwen tts: parse response'. The response succeeded at HTTP level but is not the documented envelope.","triggerScenarios":"json.Unmarshal(body, &result) fails: body is HTML (proxy/auth portal page), truncated JSON, gzip/content-type mismatch, or an undocumented error envelope shape.","commonSituations":"A captive portal or corporate proxy returning HTML with 200; an API gateway returning a JSON error with a different field layout; binary/garbage body due to missing Accept-Encoding handling; provider API version drift changing the response schema.","solutions":["Log the raw body on this failure to see what was actually returned.","Check whether a proxy/intermediary is rewriting the response (HTML login pages, WAF blocks).","Verify the BaseURL points at the JSON API endpoint, not a console or redirect URL.","Confirm the provider API version still matches the response schema in core/tts.go."],"exampleFix":"// before\n// silent assumption: body is valid JSON\n// after\nif !json.Valid(body) {\n    slog.Error(\"qwen tts non-JSON body\", \"prefix\", string(body[:min(200, len(body))]))\n}\nif err := json.Unmarshal(body, &result); err != nil { ... }","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"func isParseResponseError(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"qwen tts: parse response\")\n}","tryCatchPattern":"audio, _, err := q.Synthesize(ctx, text, opts)\nif isParseResponseError(err) {\n    slog.Error(\"qwen tts returned non-JSON body — check proxy/endpoint\", \"err\", err)\n    return fmt.Errorf(\"TTS service returned an unexpected response\")\n}","preventionTips":["Log the raw response body whenever unmarshal fails.","Ensure no corporate proxy/WAF rewrites API responses.","Pin and periodically review the API version behind BaseURL.","Check Content-Type of responses in integration tests."],"tags":["tts","qwen","json","api"],"backgroundTag":"json-unmarshal-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"}