Troubleshooting the AssemblyAI API: The importance of retrying requests after server or upload errors
Learn about troubleshooting common customer issues in the AssemblyAI API directly from our customer support team.



While uncommon, you may occasionally encounter upload or server errors that can temporarily interrupt the transcription process when using the AssemblyAI API. These issues are usually momentary, and retrying the request can often resolve the issue, a key practice for building with the confidence and reliability that industry research identifies as critical for success.
In this article, we'll explore why retrying your request is a valuable first step, how to implement robust retry logic, and other best practices for handling API errors.
Understanding AssemblyAI server and upload errors
AssemblyAI API returns two types of retryable errors: upload errors (422 status from /v2/upload) and server errors (500 status from /v2/transcript). Both indicate temporary failures that resolve with proper retry logic.
- Upload Errors: These happen at the initial file submission stage, often before any processing begins. This could be due to a momentary issue with our upload service or a problem with the file itself, like an empty audio file.
- Server Errors: These occur during the transcription process after a file has been successfully uploaded. They typically indicate a high load on our servers, a transient issue that interrupted processing, or an edge case where an AI model fails on a specific file.
Here's a quick reference for the most common error types you'll encounter:
Implementing robust retry logic with the Python SDK
While it's possible to handle upload and server errors separately by making direct HTTP requests, the modern AssemblyAI Python SDK simplifies this process, as native SDKs with built-in error handling save developers from writing boilerplate retry logic.
The transcribe() method handles file uploading, transcription submission, and status polling in a single call. This means we can implement one robust retry strategy to handle transient failures at any stage.
We recommend using a library like tenacity to add exponential backoff to SDK calls. This approach is cleaner and more reliable than manual loops.
First, install the necessary libraries:
pip install assemblyai tenacity
Here's how to implement a resilient transcription function that automatically retries on transient errors, such as 422 upload failures or 5xx server errors:
import assemblyai as aai
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception
# Configure your API key
aai.settings.api_key = "YOUR_API_KEY"
# Define a function to check for retryable errors.
# This helps distinguish transient issues from permanent ones.
def is_retryable(error: BaseException) -> bool:
if isinstance(error, aai.errors.AssemblyAIError):
# Check for specific, temporary error messages from the API
msg = str(error).lower()
if "server error" in msg or "upload failed" in msg:
print(f"Retryable error detected: {error}")
return True
return False
@retry(
stop=stop_after_attempt(5),
wait=wait_exponential(multiplier=1, min=2, max=60),
retry=retry_if_exception(is_retryable)
)
def transcribe_with_retries(file_path: str):
"""
Transcribes a file using the AssemblyAI SDK with exponential backoff
for transient upload or server errors.
"""
print(f"Attempting to transcribe {file_path}...")
transcriber = aai.Transcriber()
# The .transcribe() method handles the entire process.
# If it fails with a retryable error, tenacity will re-run this function.
transcript = transcriber.transcribe(file_path)
# If the transcription job itself fails with a terminal error (e.g., invalid audio),
# we raise an exception. If this error is not "retryable", tenacity will stop.
if transcript.status == aai.TranscriptStatus.error:
raise aai.errors.AssemblyAIError(f"Transcription job failed with error: {transcript.error}")
return transcript
# --- Example Usage ---
if __name__ == "__main__":
AUDIO_FILE_URL = "https://storage.googleapis.com/aai-web-samples/espn-bears.m4a"
try:
final_transcript = transcribe_with_retries(AUDIO_FILE_URL)
print("\nTranscription successful!")
print(f"Transcript ID: {final_transcript.id}")
print(f"Text: {final_transcript.text[:150]}...")
except aai.errors.AssemblyAIError as e:
print(f"\nTranscription failed after all retries: {e}")
except Exception as e:
print(f"\nAn unexpected error occurred: {e}")
This single, resilient function replaces the need for separate upload and server error handlers. It gracefully retries on temporary issues and fails definitively on permanent problems, making your application more robust.
For more detailed examples, our support team has created comprehensive cookbooks for handling both upload errors and server errors with the Python SDK.
Why retrying matters
In many of these cases, a simple retry is all that's needed to successfully upload your file or process the request, which is why retrying failed jobs is a core component of robust, large-scale transcription architectures.
Here's why retrying can improve your overall transcription workflow:
- Temporary issues get resolved: Most upload or server errors are temporary and are related to external factors, such as momentary server load, or temporary degraded performance issues on our end. Retrying after a short interval gives these issues time to resolve.
- Ensures continuity of service: In a busy transcription service, many requests are handled simultaneously. Retrying helps ensure that your request gets processed once any temporary obstacles are cleared.
Compare different retry strategies to choose the best approach for your use case:
Best practices for error handling and monitoring
As noted in guides for API implementation, robust error handling and polling strategies are required for production applications, which need more sophisticated approaches than basic retries.
Use exponential backoff with jitter
Increase wait time exponentially: 1s, 2s, 4s, 8s. Add random jitter to prevent synchronized retries.
# Example implementation with jitter
import random
def calculate_backoff_with_jitter(attempt: int, base: int = 1) -> float:
"""Calculate exponential backoff with jitter."""
exponential_wait = base * (2 ** attempt)
jitter = random.uniform(0, exponential_wait * 0.1)
return min(exponential_wait + jitter, 60) # Cap at 60 seconds
Set maximum retry limits
Limit retries to 3-5 attempts to prevent infinite loops.
Implement structured logging
Log request ID, error message, and timestamp for debugging:
import logging
from datetime import datetime
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def log_api_error(error_type: str, request_id: str, attempt: int, error_msg: str):
"""Log API errors with context for debugging."""
logger.error(
f"API Error | Type: {error_type} | "
f"RequestID: {request_id} | "
f"Attempt: {attempt} | "
f"Time: {datetime.utcnow().isoformat()} | "
f"Message: {error_msg}"
)
Implement circuit breakers
Circuit breakers prevent cascading failures by stopping requests when error rates exceed thresholds. Use for high-volume applications:
class CircuitBreaker:
def __init__(self, failure_threshold: int = 5, recovery_timeout: int = 60):
self.failure_threshold = failure_threshold
self.recovery_timeout = recovery_timeout
self.failure_count = 0
self.last_failure_time = None
self.state = 'closed' # closed, open, half-open
def call(self, func, *args, **kwargs):
if self.state == 'open':
if time.time() - self.last_failure_time > self.recovery_timeout:
self.state = 'half-open'
else:
raise Exception("Circuit breaker is open")
try:
result = func(*args, **kwargs)
if self.state == 'half-open':
self.state = 'closed'
self.failure_count = 0
return result
except Exception as e:
self.failure_count += 1
self.last_failure_time = time.time()
if self.failure_count >= self.failure_threshold:
self.state = 'open'
raise e
Tips, tricks, and troubleshooting
Key troubleshooting strategies:
- Optimize retry intervals:
- Batch processing: Use longer delays (30-60s)
- Real-time apps: Start with 1s, increase exponentially
- Default cookbook setting: 5s intervals
- Double-check your file: Ensure that the file you're uploading meets the required file format and size limits. If your file is too large or in an unsupported format, it will fail repeatedly. Additionally, if your file is empty (contains no audio), it will always fail at the upload step.
- Monitor your retry patterns: Track how often retries are needed and at what attempt they succeed. This data can help you optimize your retry strategy and identify patterns in failures.
- Consider async processing: For batch operations, implement asynchronous retry queues that can handle failures gracefully without blocking other operations.
What if the problem persists
If retries fail after confirming file validity, contact support. Verify format compliance, size limits, and audio content first.
Before contacting support, verify:
- The audio file contains actual audio content (not silence)
- The file format is supported (MP3, MP4, WAV, FLAC, etc.)
- The file size is within limits (up to 5GB for files submitted via a publicly accessible URL, and up to 2.2GB for local file uploads).
- Your API key has the necessary permissions
- You're not hitting rate limits
In this case, please contact our support team for assistance in diagnosing the issue. When contacting support, include:
- The request ID or transcript ID
- The exact error message
- The timestamp of the error
- A sample of the problematic audio file (if possible)
Building robust error handling is key to creating a reliable Voice AI application, which directly impacts the quality and performance that a recent survey found is a top priority for 58% of tech leaders.
By implementing smart retry logic with exponential backoff, you can handle most transient issues automatically and ensure a smoother experience for your users. Ready to build resilient Voice AI applications? Try our API for free and implement these best practices in your next project.
Frequently asked questions about AssemblyAI API error handling
What is an API server error?
An API server error is a 500-level HTTP status indicating temporary server-side processing failures. Resolve with exponential backoff retry logic.
How do I fix a 500 internal server error from the API?
Implement exponential backoff starting at 1s (1s, 2s, 4s, 8s) with jitter. Contact support with request ID if errors persist after 5 attempts.
What's the difference between retryable and non-retryable errors?
Retryable errors (5xx, 422) are temporary and resolve with retry logic. Non-retryable errors (401, 400) are permanent failures requiring code fixes.
How do I implement exponential backoff with the AssemblyAI Python SDK?
Wrap SDK calls with retry decorators using tenacity or backoff libraries. Use time.sleep(2 ** attempt) for custom implementations.
What are the rate limits and how do they affect retry strategies?
AssemblyAI manages high volume by queueing asynchronous transcription requests that exceed your account's concurrency limit (e.g., 200+ for paid accounts). While this isn't a hard rate limit that causes errors, your retry strategy should still use exponential backoff to handle transient server errors gracefully and avoid overwhelming the API.
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.


.png)


