{"record":{"id":"7bd699a257188c3e","repo":"sipeed/picoclaw","slug":"failed-to-read-response-w","errorCode":null,"errorMessage":"failed to read response: %w","messagePattern":"failed to read response: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/audio/asr/elevenlabs_transcriber.go","lineNumber":117,"sourceCode":"\treq.Header.Set(\"Xi-Api-Key\", t.apiKey)\n\n\tlogger.DebugCF(\"voice\", \"Sending transcription request to ElevenLabs API\", map[string]any{\n\t\t\"url\":                url,\n\t\t\"request_size_bytes\": requestBody.Len(),\n\t\t\"file_size_bytes\":    fileInfo.Size(),\n\t})\n\n\tresp, err := t.httpClient.Do(req)\n\tif err != nil {\n\t\tlogger.ErrorCF(\"voice\", \"Failed to send request\", map[string]any{\"error\": err})\n\t\treturn nil, fmt.Errorf(\"failed to send request: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\tbody, err := io.ReadAll(resp.Body)\n\tif err != nil {\n\t\tlogger.ErrorCF(\"voice\", \"Failed to read response\", map[string]any{\"error\": err})\n\t\treturn nil, fmt.Errorf(\"failed to read response: %w\", err)\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\tlogger.ErrorCF(\"voice\", \"ElevenLabs API error\", map[string]any{\n\t\t\t\"status_code\": resp.StatusCode,\n\t\t\t\"response\":    string(body),\n\t\t})\n\t\treturn nil, fmt.Errorf(\"ElevenLabs API error (status %d): %s\", resp.StatusCode, string(body))\n\t}\n\n\tlogger.DebugCF(\"voice\", \"Received response from ElevenLabs API\", map[string]any{\n\t\t\"status_code\":         resp.StatusCode,\n\t\t\"response_size_bytes\": len(body),\n\t})\n\n\tvar result TranscriptionResponse\n\tif err := json.Unmarshal(body, &result); err != nil {\n\t\tlogger.ErrorCF(\"voice\", \"Failed to unmarshal response\", map[string]any{\"error\": err})","sourceCodeStart":99,"sourceCodeEnd":135,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/audio/asr/elevenlabs_transcriber.go#L99-L135","documentation":"Thrown when io.ReadAll(resp.Body) fails in ElevenLabsTranscriber.Transcribe — the HTTP status line was received and the body started streaming, but the read aborted. Typical causes: connection reset by the peer or an intermediary mid-body, keep-alive socket closed, or ctx cancelled while the body streams. The defer resp.Body.Close() runs afterwards, so no fd leak.","triggerScenarios":"ElevenLabs/CDN edge drops the connection mid-response; a proxy enforces a shorter body timeout than the client; ctx is cancelled while a large JSON transcript streams back.","commonSituations":"Flaky mobile/edge networks; nginx/Envoy between client and API with aggressive proxy_read_timeout; long audio jobs whose transcript response is large.","solutions":["Retry once — a fresh request usually succeeds because the failure is mid-stream.","Check intermediary proxy timeouts if it recurs in one environment only.","Propagate ctx instead of context.Background() so cancellation is intentional, not accidental."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":"func isMidBodyDrop(err error) bool {\n    var netErr net.Error\n    return errors.As(err, &netErr) || errors.Is(err, io.ErrUnexpectedEOF)\n}","tryCatchPattern":"resp, err := el.Transcribe(ctx, path)\nif err != nil && isMidBodyDrop(err) {\n    // mid-response drop: idempotent POST of the same file, safe to retry once\n    resp, err = el.Transcribe(ctx, path)\n}","preventionTips":["Raise intermediary proxy body/read timeouts if the path crosses nginx/Envoy.","Retry once on unexpected EOF — the request already succeeded server-side."],"tags":["network","io","elevenlabs","retry","go"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}