zeroclaw-labs/zeroclaw · error

AssemblyAI poll error ({}): {}

Error message

AssemblyAI poll error ({}): {}

What it means

Step three of the AssemblyAI pipeline: the poll loop GETs the transcript status endpoint, and one poll returned non-2xx. A single failed HTTP poll aborts the whole transcription immediately (the code bails instead of skipping the round), even if the job itself is fine. The status and body 'error' text are embedded.

Source

Thrown at crates/zeroclaw-channels/src/transcription.rs:573

            tokio::time::sleep(poll_interval).await;

            let poll_resp = client
                .get(&poll_url)
                .header("Authorization", &self.api_key)
                .timeout(std::time::Duration::from_secs(30))
                .send()
                .await
                .context("Failed to poll AssemblyAI transcription")?;

            let poll_status = poll_resp.status();
            let poll_body: serde_json::Value = poll_resp
                .json()
                .await
                .context("Failed to parse AssemblyAI poll response")?;

            if !poll_status.is_success() {
                let error_msg = poll_body["error"].as_str().unwrap_or("unknown poll error");
                bail!("AssemblyAI poll error ({}): {}", poll_status, error_msg);
            }

            let status_str = poll_body["status"].as_str().unwrap_or("unknown");

            match status_str {
                "completed" => {
                    let text = poll_body["text"]
                        .as_str()
                        .context("AssemblyAI response missing 'text'")?
                        .to_string();
                    return Ok(text);
                }
                "error" => {
                    let error_msg = poll_body["error"]
                        .as_str()
                        .unwrap_or("unknown transcription error");
                    bail!("AssemblyAI transcription failed: {}", error_msg);
                }

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. 429 — space out concurrent transcriptions; AssemblyAI's poll loop already sleeps between rounds, but many parallel jobs multiply request volume
  2. 5xx — retry the whole transcribe(); the upload will be repeated but the job usually succeeds
  3. 404 — verify the api_key belongs to the account that created the transcript (no region-split keys)
  4. 401 — update the api_key in [transcription.assemblyai]
Defensive patterns

Strategy: retry

Try / catch

match provider.transcribe(&audio, name).await {
    Ok(text) => Ok(text),
    Err(e) if e.to_string().contains("AssemblyAI poll error") => {
        // a single failed poll kills a healthy job — retry the whole transcription
        retry_with_backoff(|| provider.transcribe(&audio, name)).await
    }
    other => other,
}

Prevention

When it happens

Trigger: GET /v2/transcript/{id} returns non-success during the polling loop: 401 invalid api_key, 404 unknown/expired transcript id, 429 rate limited, 5xx transient — each of these immediately fails the transcription.

Common situations: A brief network hiccup or a 429 during the poll window kills an otherwise healthy job; AssemblyAI returning 404 for a transcript purged after 30 days is not an issue here, but a 404 right after creation indicates an account/region mismatch; polling burst from many concurrent transcriptions tripping rate limits.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/ba8b04e02e50b5bd. Report an issue: GitHub.