{"record":{"id":"9f2402b6884352a6","repo":"zeroclaw-labs/zeroclaw","slug":"assemblyai-upload-error","errorCode":null,"errorMessage":"AssemblyAI upload error ({}): {}","messagePattern":"AssemblyAI upload error \\((.+?)\\): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-channels/src/transcription.rs","lineNumber":509,"sourceCode":"        let upload_resp = client\n            .post(\"https://api.assemblyai.com/v2/upload\")\n            .header(\"Authorization\", &self.api_key)\n            .header(\"Content-Type\", \"application/octet-stream\")\n            .body(audio_data.to_vec())\n            .timeout(std::time::Duration::from_secs(TRANSCRIPTION_TIMEOUT_SECS))\n            .send()\n            .await\n            .context(\"Failed to upload audio to AssemblyAI\")?;\n\n        let upload_status = upload_resp.status();\n        let upload_body: serde_json::Value = upload_resp\n            .json()\n            .await\n            .context(\"Failed to parse AssemblyAI upload response\")?;\n\n        if !upload_status.is_success() {\n            let error_msg = upload_body[\"error\"].as_str().unwrap_or(\"unknown error\");\n            bail!(\"AssemblyAI upload error ({}): {}\", upload_status, error_msg);\n        }\n\n        let upload_url = upload_body[\"upload_url\"]\n            .as_str()\n            .context(\"AssemblyAI upload response missing 'upload_url'\")?;\n\n        // Step 2: Create transcription job.\n        let transcript_req = serde_json::json!({\n            \"audio_url\": upload_url,\n        });\n\n        let create_resp = client\n            .post(\"https://api.assemblyai.com/v2/transcript\")\n            .header(\"Authorization\", &self.api_key)\n            .json(&transcript_req)\n            .timeout(std::time::Duration::from_secs(TRANSCRIPTION_TIMEOUT_SECS))\n            .send()\n            .await","sourceCodeStart":491,"sourceCodeEnd":527,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-channels/src/transcription.rs#L491-L527","documentation":"AssemblyAI transcription is a three-step pipeline (upload bytes, create transcript, poll), and this error is step one failing: the POST that uploads raw audio to AssemblyAI's upload endpoint returned non-2xx. The status and the 'error' field of the response body are embedded. Nothing was queued — the failure happened before a transcript was created.","triggerScenarios":"POST to AssemblyAI's /v2/upload with the audio bytes returns non-success: 401 invalid [transcription.assemblyai] api_key, 400 malformed or undecodable audio payload, 429 rate limited, 5xx upstream incident.","commonSituations":"Wrong or rotated AssemblyAI API key; audio passed the 25 MB validate_audio() check but is corrupt or in a container AssemblyAI's uploader rejects; free-tier throttling on bursts of voice notes.","solutions":["401/403 — fix the api_key under [transcription.assemblyai]","400 — re-encode the audio to a mainstream format (mp3, wav, flac, ogg) and retry; verify the file is not truncated","429/5xx — retry the transcribe() call with exponential backoff","If it persists, check status.assemblyai.com for an upload-endpoint incident"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match provider.transcribe(&audio, name).await {\n    Ok(text) => Ok(text),\n    Err(e) if e.to_string().contains(\"AssemblyAI upload error\") => {\n        // transport/upload step failed: safe to retry the whole call once or twice\n        retry_with_backoff(|| provider.transcribe(&audio, name)).await\n    }\n    other => other,\n}","preventionTips":["Keep the AssemblyAI key in a secret source that rotates cleanly","Pre-encode audio to mp3/wav/flac so the upload step never rejects the payload","Retry once with backoff — upload failures are frequently transient"],"tags":["assemblyai","upload","http-status","api-key","transcription"],"backgroundTag":"speech-to-text-api-error","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}