{"record":{"id":"0162a9762934d85a","repo":"sipeed/picoclaw","slug":"elevenlabs-api-error-status-d-s","errorCode":null,"errorMessage":"ElevenLabs API error (status %d): %s","messagePattern":"ElevenLabs API error \\(status (.+?)\\): (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/audio/asr/elevenlabs_transcriber.go","lineNumber":125,"sourceCode":"\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})\n\t\treturn nil, fmt.Errorf(\"failed to unmarshal response: %w\", err)\n\t}\n\n\tlogger.InfoCF(\"voice\", \"ElevenLabs transcription completed successfully\", map[string]any{\n\t\t\"text_length\":           len(result.Text),\n\t\t\"language\":              result.Language,\n\t\t\"transcription_preview\": utils.Truncate(result.Text, 50),\n\t})","sourceCodeStart":107,"sourceCodeEnd":143,"githubUrl":"https://github.com/sipeed/picoclaw/blob/49183d7e8daed0dba89ddbb6fcb60089401d9680/pkg/audio/asr/elevenlabs_transcriber.go#L107-L143","documentation":"Thrown when the ElevenLabs speech-to-text endpoint answers with any status other than 200. The message embeds the numeric status and the raw response body, so the upstream reason travels with the error. Common mappings: 401 invalid/missing Xi-Api-Key, 422 validation (unsupported audio format, file too large, wrong model_id), 429 rate limit or concurrency cap, 5xx upstream failure. Note this error is built with %d/%s, not %w — the status code is not programmatically unwrappable by callers.","triggerScenarios":"t.apiKey empty or revoked (401); audio format outside Scribe's supported set (422 with file_mime_type error); recording exceeds size/duration limits (422); modelID not scribe_v1 (constructor forces scribe_v1, so mainly custom apiBase deployments); burst traffic hitting free-tier concurrency (429); ElevenLabs incident (5xx).","commonSituations":"API key from a deleted workspace; 8kHz telephony WAV or exotic codec rejected; long dictations over the size cap; parallel transcriptions exceeding the plan's concurrency; status page incident.","solutions":["Read the embedded body in the error string — it states the exact violation (e.g. 'file_mime_type is not supported').","401: verify the XI-Api-Key value and that the key is active in the ElevenLabs dashboard.","422: convert the audio to a supported format (16kHz+ WAV/MP3/Opus) and check duration/size caps before upload.","429: back off (Retry-After header) and serialize or throttle transcription jobs to the plan's concurrency.","5xx: retry with exponential backoff; check status.elevenlabs.io.","Improve diagnosability: wrap with %w and truncate the body instead of inlining it fully."],"exampleFix":"// before (library code)\nreturn nil, fmt.Errorf(\"ElevenLabs API error (status %d): %s\", resp.StatusCode, string(body))\n\n// after: keep it unwrappable and bounded\ntype APIError struct {\n    StatusCode int\n    Body       string\n}\nfunc (e *APIError) Error() string {\n    return fmt.Sprintf(\"ElevenLabs API error (status %d): %s\", e.StatusCode, utils.Truncate(e.Body, 500))\n}\nreturn nil, &APIError{StatusCode: resp.StatusCode, Body: string(body)}","handlingStrategy":"try-catch","validationCode":"// Pre-flight the key without spending a transcription call:\nif t.apiKey == \"\" { return errors.New(\"ElevenLabs API key missing\") }\n// Validate audio constraints before upload (Scribe limits):\nfi, err := os.Stat(path)\nif err != nil { return err }\nif fi.Size() > 500*1024*1024 { return errors.New(\"audio too large for Scribe\") }\nswitch strings.ToLower(filepath.Ext(path)) {\ncase \".wav\", \".mp3\", \".m4a\", \".mp4\", \".webm\", \".flac\", \".ogg\", \".opus\", \".aac\":\ndefault:\n    return fmt.Errorf(\"possibly unsupported audio extension: %s\", filepath.Ext(path))\n}","typeGuard":"func elevenLabsStatus(err error) (int, string, bool) {\n    m := regexp.MustCompile(`ElevenLabs API error \\(status (\\d+)\\): (.*)`).FindStringSubmatch(err.Error())\n    if m == nil { return 0, \"\", false }\n    code, _ := strconv.Atoi(m[1])\n    return code, m[2], true\n}","tryCatchPattern":"if _, err := el.Transcribe(ctx, path); err != nil {\n    if code, body, ok := elevenLabsStatus(err); ok {\n        switch {\n        case code == 401: return errors.New(\"invalid ElevenLabs API key\")\n        case code == 422: return fmt.Errorf(\"audio rejected: %s\", body)\n        case code == 429: time.Sleep(30 * time.Second) /* honor Retry-After */ ; return retry()\n        case code >= 500: return retryWithBackoff()\n        }\n    }\n    return err\n}","preventionTips":["Never send an empty API key; assert it at startup.","Normalize audio to 16kHz WAV/Opus before upload to avoid 422 format rejections.","Throttle concurrent transcriptions to the plan's concurrency to avoid 429.","Log the embedded response body verbatim — it names the exact violated constraint."],"tags":["api","http-status","elevenlabs","rate-limit","authentication","go"],"backgroundTag":null,"analyzedSha":"49183d7e8daed0dba89ddbb6fcb60089401d9680","analyzedAt":"2026-08-15T21:55:41.315Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}