Billionmail/BillionMail · error
cartesia clone API error %d: %s
Error message
cartesia clone API error %d: %s
What it means
CloneVoice in the video_gen package calls the Cartesia /voices/clone endpoint and requires an exact HTTP 200 response. When Cartesia returns any other status code (401, 400, 429, 5xx, etc.), the non-200 body is read and wrapped in this error, so the message contains the raw API error payload from Cartesia. It is a remote-API rejection of the clone request, not a local failure.
Source
Thrown at core/internal/service/video_gen/voice.go:156
AudioURL: audioURL,
Language: "en",
}
httpReq, err := BuildCloneRequest(cfg, req)
if err != nil {
return nil, err
}
httpReq = httpReq.WithContext(ctx)
resp, err := cfg.doHTTP(httpReq)
if err != nil {
return nil, fmt.Errorf("cartesia clone API call: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
body, _ := io.ReadAll(resp.Body)
return nil, fmt.Errorf("cartesia clone API error %d: %s", resp.StatusCode, string(body))
}
var result VoiceCloneResponse
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
return nil, fmt.Errorf("decode clone response: %w", err)
}
return &result, nil
}
// TextToSpeech generates audio from text using a Cartesia voice.
// Returns the path to the output WAV file.
func TextToSpeech(ctx context.Context, cfg VoiceConfig, voiceID, transcript, filename string) (string, error) {
if err := os.MkdirAll(cfg.OutputDir, 0755); err != nil {
return "", fmt.Errorf("create output dir: %w", err)
}
req := TTSRequest{
VoiceID: voiceID,View on GitHub (pinned to fc36c76c05)
Solutions
- Log the embedded Cartesia body — it names the exact reason (invalid key, bad clip, quota).
- Verify CARTESIA_API_KEY is set and valid for the account.
- Check the audioURL is publicly fetchable, uses a supported audio format, and is not expired.
- Check Cartesia status/quota; apply backoff and retry for 429/5xx.
- Confirm the Cartesia-Version header (2024-06-10) is still accepted by your account.
Example fix
// before
resp, err := cfg.doHTTP(httpReq)
if err != nil { ... }
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("cartesia clone API error %d: %s", resp.StatusCode, string(body))
}
// after
if cfg.APIKey == "" {
return nil, errors.New("cartesia API key missing")
}
if u, err := url.Parse(audioURL); err != nil || u.Scheme != "https" {
return nil, fmt.Errorf("invalid audio URL %q", audioURL)
}
resp, err := cfg.doHTTP(httpReq)
if err != nil { ... }
switch {
case resp.StatusCode == http.StatusTooManyRequests || resp.StatusCode >= 500:
return nil, retryableError{fmt.Errorf("cartesia clone API error %d", resp.StatusCode)}
case resp.StatusCode != http.StatusOK:
return nil, fmt.Errorf("cartesia clone API error %d: %s", resp.StatusCode, string(body))
} Defensive patterns
Strategy: validation
Validate before calling
if cfg.APIKey == "" {
return errors.New("CARTESIA_API_KEY is not set")
}
if audioURL == "" {
return errors.New("audioURL is required for voice cloning")
}
u, err := url.Parse(audioURL)
if err != nil || (u.Scheme != "https" && u.Scheme != "http") {
return fmt.Errorf("invalid audio URL: %q", audioURL)
}
resp, err := http.Head(audioURL)
if err == nil && resp.StatusCode != http.StatusOK {
return fmt.Errorf("audio URL not fetchable: %d", resp.StatusCode)
} Try / catch
resp, err := video_gen.CloneVoice(ctx, cfg, name, audioURL)
if err != nil {
var apiErr *video_gen.APIError
if strings.Contains(err.Error(), "cartesia clone API error 4") {
// non-retryable: fix key/URL/input
log.Fatalf("clone rejected: %v", err)
}
// 429/5xx: retry with backoff
} Prevention
- Set and verify CARTESIA_API_KEY before deploying
- Pre-check audio clip URLs are public, https, and unexpired
- Monitor 429 responses and back off instead of hammering the API
- Keep the Cartesia-Version header aligned with the account's supported version
When it happens
Trigger: Calling CloneVoice when the X-API-Key is invalid/expired (401), the clip audio URL is unreachable or an invalid format (400), quota/rate limits are hit (429), or Cartesia has a server-side outage (5xx).
Common situations: Missing or misconfigured CARTESIA_API_KEY env var, audio clip URL behind auth or expired presigned URL, unsupported audio format/language, exceeding account voice-clone limits, Cartesia API version incompatibility.
Related errors
- cartesia TTS API error %d: %s
- unexpected API response: %d %s
- voice clone: %w
- marshal clone request: %w
- create clone request: %w
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/3bbaacc2189c1e60.
Report an issue: GitHub.