I've watched transcription pipelines fail in ways that unit tests never catch. A 502 during a batch job at 2am. A timeout that leaves half your queue in limbo. A retry storm that triggers rate limits across three services. In our complete guide to speech-to-text for AI agents, we covered the full voice pipeline. This guide focuses on speech-to-text API error handling: retries, timeouts, and fallback patterns for production workloads.
If you're piping audio through Privocio, OpenAI Whisper API, or Deepgram, the HTTP layer is where most failures surface.
Why STT error handling is different
Speech-to-text requests aren't like a typical REST call. You're uploading multi-megabyte audio files, waiting 5-30 seconds for processing, and often chaining the result into an LLM agent.
I've debugged three recurring patterns across production deployments:
- Long-running requests: a 60-second audio file can take 15+ seconds to transcribe. Default 5-second HTTP timeouts will kill valid jobs.
- Idempotency gaps: retrying the same file upload without tracking job IDs can produce duplicate transcripts or double billing on usage-based APIs.
- Partial failures in batch pipelines: when you're processing 500 files via webhooks, one bad file shouldn't block the other 499.
The fix isn't complicated, but it has to be deliberate: explicit timeout budgets, classified retry rules, and a dead-letter path for files that won't transcribe.
HTTP error codes that matter
Not every HTTP error deserves a retry. I've burned hours debugging retry loops that hammered a 400 Bad Request because the audio format was wrong. Here's the classification I use across every STT integration:
| Status | Meaning | Retry? | Action |
|---|---|---|---|
| 400 | Bad request (invalid format, missing field) | No | Log, fix audio, send to dead-letter queue |
| 401 | Invalid API key | No | Alert ops — credentials rotated or expired |
| 413 | Payload too large | No | Split or compress audio with FFmpeg |
| 429 | Rate limited | Yes (with backoff) | Respect Retry-After header, reduce concurrency |
| 500 | Server error | Yes (limited) | Retry 2-3 times with exponential backoff |
| 502/503/504 | Gateway/timeout | Yes | Retry with longer timeout; check provider status |
The 429 case is where teams get hurt. AssemblyAI and Google Cloud Speech-to-Text both enforce concurrency caps. If your retry logic fires immediately on 429, you'll make it worse. Always parse the Retry-After header when present and cap your concurrency before you hit the limit. Our rate limits guide walks through the numbers across major providers.
Retry patterns that work
I've settled on a simple retry policy that works across Privocio, Whisper, and AWS Transcribe:
- Max 3 retries for 5xx and network errors. Beyond that, the failure is probably not transient.
- Exponential backoff with jitter: base delay 1s, multiply by 2 each attempt, add random 0-500ms to prevent thundering herd.
- Never retry 4xx except 429, and even then respect the provider's backoff signal.
- Track attempt count per job ID in queue metadata so webhook retries don't double-process.
For async pipelines using webhooks, push retry logic into your queue worker, not the webhook handler. The handler should acknowledge receipt fast and let the worker manage backoff. We cover that in our async transcription with webhooks guide.
Timeouts and circuit breakers
Timeout math is where I see the most preventable outages. A speech-to-text call has three phases: upload, processing, and response. Your timeout needs to cover all three.
My rule of thumb: timeout = (audio_duration_seconds × 0.5) + 10 seconds, with a floor of 30 seconds and a ceiling of 300 seconds. A 2-minute file gets a 70-second timeout.
For circuit breakers, I open the circuit after 5 consecutive failures within 60 seconds. Close it after 30 seconds and send a single probe request. For streaming agents, see our real-time vs batch guide.
Fallback patterns for production pipelines
Retries fix transient failures. Fallbacks fix everything else.
I've deployed three fallback tiers across client pipelines:
- Secondary provider: route failed jobs to a backup API after retries exhaust. Keep output formats compatible (we use Clean mode on Privocio so downstream LLM prompts don't change). Compare providers in our developer API comparison.
- Dead-letter queue: files that fail after all retries go to a DLQ with the error code, attempt count, and original file path. Review weekly; most DLQ items are bad audio, not API bugs.
- Graceful degradation: for agent workloads, return a partial transcript or a "transcription unavailable" signal to the LLM instead of crashing the agent loop.
On Privocio, fixed pricing means retries don't inflate your bill the way they would on per-minute APIs.
Frequently Asked Questions
Should I retry a 400 Bad Request from a speech-to-text API?
No. A 400 means your request is malformed — wrong file format, missing parameters, or corrupted audio. Retrying won't fix it. Log the error, inspect the file with FFmpeg, and route it to your dead-letter queue.
How many retries are safe for transcription APIs?
Three retries with exponential backoff covers most transient failures. I've rarely seen a 502 resolve on the fourth attempt. If you're hitting rate limits (429), fix your concurrency first — retries alone won't help.
What's the right timeout for a 5-minute audio file?
Use the formula: (duration × 0.5) + 10 seconds, capped at 300 seconds. For a 5-minute file, that's 160 seconds. Set your HTTP client timeout slightly higher to account for upload time on slow connections.
Can I use webhooks instead of polling to avoid timeout issues?
Yes, and I recommend it for batch workloads. Submit the job, get a job ID, and let the provider POST results to your webhook when ready. Your client timeout only covers the submission, not the full transcription. See our webhook transcription guide.
Conclusion: Plan for Failure, Not Hope
Speech-to-text API error handling isn't glamorous work, but it's the difference between a pipeline that survives a provider outage and one that loses a day's worth of transcripts. Classify your HTTP errors, cap retries at three with jitter, set timeouts based on audio duration, and keep a dead-letter queue for the files that won't budge.
If you're building voice agents, start with explicit error handling in your STT layer before you optimize latency. Check our pricing page for predictable costs on retries, and read the full speech-to-text for AI agents guide for pipeline architecture.
Image Credits:
Cover image sourced from Unsplash (Unsplash License).