{"record":{"id":"ff7eeab7a23cb0b4","repo":"Billionmail/BillionMail","slug":"cartesia-tts-api-call-w","errorCode":null,"errorMessage":"cartesia TTS API call: %w","messagePattern":"cartesia TTS API call: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/internal/service/video_gen/voice.go","lineNumber":189,"sourceCode":"\t}\n\n\treq := TTSRequest{\n\t\tVoiceID:      voiceID,\n\t\tTranscript:   transcript,\n\t\tModelID:      \"sonic-2\",\n\t\tOutputFormat: DefaultTTSOutputFormat(),\n\t\tLanguage:     \"en\",\n\t}\n\n\thttpReq, err := BuildTTSRequest(cfg, req)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\thttpReq = httpReq.WithContext(ctx)\n\n\tresp, err := cfg.doHTTP(httpReq)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"cartesia TTS API call: %w\", err)\n\t}\n\tdefer resp.Body.Close()\n\n\tif resp.StatusCode != http.StatusOK {\n\t\tbody, _ := io.ReadAll(resp.Body)\n\t\treturn \"\", fmt.Errorf(\"cartesia TTS API error %d: %s\", resp.StatusCode, string(body))\n\t}\n\n\toutPath := filepath.Join(cfg.OutputDir, filename)\n\tf, err := os.Create(outPath)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"create output file: %w\", err)\n\t}\n\tdefer f.Close()\n\n\tif _, err := io.Copy(f, resp.Body); err != nil {\n\t\treturn \"\", fmt.Errorf(\"write audio data: %w\", err)\n\t}","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/Billionmail/BillionMail/blob/fc36c76c050c3775c5e899faf7403cf0262d2744/core/internal/service/video_gen/voice.go#L171-L207","documentation":"TextToSpeech posts to Cartesia /tts/bytes via cfg.doHTTP; if the HTTP round trip itself fails — DNS failure, connection refused/timeout, TLS error, or rate-limited client rejection — the error is wrapped as 'cartesia TTS API call'. This is a transport-level failure before any status code is available.","triggerScenarios":"No network/DNS resolution for api.cartesia.ai, connection timeout exceeded, TLS certificate problems, an HTTP proxy blocking egress, or the RateLimitedClient refusing the request when its budget is exhausted.","commonSituations":"Egress firewall in Docker/K8s blocking outbound 443, expired system CA bundle, missing HTTP_PROXY/HTTPS_PROXY config, ctx already cancelled/expired before the call, rate limiter configured too tightly.","solutions":["Inspect the wrapped %w chain for the concrete net error (timeout, refused, TLS).","Confirm outbound HTTPS to api.cartesia.ai works (curl -v https://api.cartesia.ai).","Check ctx deadlines and the RateLimitedClient budget; increase limits or wait.","Verify proxy env vars (HTTP_PROXY/HTTPS_PROXY/NO_PROXY) and CA certificates in the container.","Add retry with backoff for transient timeouts/refusals."],"exampleFix":"// before\nresp, err := cfg.doHTTP(httpReq)\nif err != nil {\n    return \"\", fmt.Errorf(\"cartesia TTS API call: %w\", err)\n}\n// after\nvar netErr net.Error\nresp, err := cfg.doHTTP(httpReq)\nif err != nil {\n    if errors.As(err, &netErr) && netErr.Timeout() {\n        return \"\", retryable(fmt.Errorf(\"cartesia TTS API call: %w\", err))\n    }\n    return \"\", fmt.Errorf(\"cartesia TTS API call: %w\", err)\n}","handlingStrategy":"retry","validationCode":"// pre-flight before calling TextToSpeech\nctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)\ndefer cancel()\nconn, err := net.DialTimeout(\"tcp\", \"api.cartesia.ai:443\", 5*time.Second)\nif err != nil {\n    return fmt.Errorf(\"cartesia unreachable: %w\", err)\n}\nconn.Close()","typeGuard":null,"tryCatchPattern":"var netErr net.Error\npath, err := video_gen.TextToSpeech(ctx, cfg, voiceID, transcript, filename)\nif err != nil {\n    if strings.Contains(err.Error(), \"cartesia TTS API call\") && errors.As(err, &netErr) && netErr.Timeout() {\n        // transient: retry with exponential backoff\n    }\n    return err\n}","preventionTips":["Configure sane timeouts on the HTTPClient / RateLimitedClient","Allow egress to api.cartesia.ai:443 in firewalls and security groups","Set HTTP(S)_PROXY correctly in restricted networks","Keep CA certificates up to date in container images"],"tags":["network","http","timeout","cartesia"],"backgroundTag":"http-request-failed","analyzedSha":"fc36c76c050c3775c5e899faf7403cf0262d2744","analyzedAt":"2026-09-05T21:28:54.019Z","contentChangedAt":"2026-09-05T21:28:54.019Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}