By Sagar Shankaran, Founder of CallSphere
Build resilient applications that gracefully handle OpenAI API errors with exponential backoff, rate limit management, circuit breakers, and fallback strategies.
Key takeaways
OpenAI API calls can fail for many reasons: rate limits, network issues, server overload, invalid requests, or authentication problems. In production, unhandled errors lead to broken user experiences and lost revenue. Building robust error handling from the start is not optional — it is a requirement for any serious AI application.
The SDK provides typed exceptions for every failure mode:
flowchart LR
INPUT(["User intent"])
PARSE["Parse plus<br/>classify"]
PLAN["Plan and tool<br/>selection"]
AGENT["Agent loop<br/>LLM plus tools"]
GUARD{"Guardrails<br/>and policy"}
EXEC["Execute and<br/>verify result"]
OBS[("Trace and metrics")]
OUT(["Outcome plus<br/>next action"])
INPUT --> PARSE --> PLAN --> AGENT --> GUARD
GUARD -->|Pass| EXEC --> OUT
GUARD -->|Fail| AGENT
AGENT --> OBS
style AGENT fill:#4f46e5,stroke:#4338ca,color:#fff
style GUARD fill:#f59e0b,stroke:#d97706,color:#1f2937
style OBS fill:#ede9fe,stroke:#7c3aed,color:#1e1b4b
style OUT fill:#059669,stroke:#047857,color:#fff
from openai import (
OpenAI,
APIError,
APIConnectionError,
RateLimitError,
APITimeoutError,
BadRequestError,
AuthenticationError,
PermissionDeniedError,
NotFoundError,
UnprocessableEntityError,
InternalServerError,
)
client = OpenAI()
try:
response = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello"}],
)
except AuthenticationError:
print("Invalid API key. Check your OPENAI_API_KEY.")
except RateLimitError:
print("Rate limit exceeded. Slow down or upgrade your plan.")
except BadRequestError as e:
print(f"Invalid request: {e.message}")
except APIConnectionError:
print("Cannot reach OpenAI servers. Check your network.")
except APITimeoutError:
print("Request timed out. Try again.")
except InternalServerError:
print("OpenAI server error. Retry after a delay.")
except APIError as e:
print(f"Unexpected API error: {e.status_code} - {e.message}")
The exception hierarchy is: APIError is the base class, with specific subclasses for each error type.
The tenacity library makes it straightforward to add retry logic with exponential backoff:
Hear it before you finish reading
Talk to a live CallSphere AI voice agent in your browser — 60 seconds, no signup.
from tenacity import retry, stop_after_attempt, wait_exponential, retry_if_exception_type
from openai import OpenAI, RateLimitError, APITimeoutError, InternalServerError
client = OpenAI()
@retry(
retry=retry_if_exception_type((RateLimitError, APITimeoutError, InternalServerError)),
wait=wait_exponential(multiplier=1, min=2, max=60),
stop=stop_after_attempt(5),
)
def call_openai(messages: list[dict], model: str = "gpt-4o") -> str:
response = client.chat.completions.create(
model=model,
messages=messages,
)
return response.choices[0].message.content
# Usage — automatically retries on transient errors
result = call_openai([{"role": "user", "content": "Explain Python generators."}])
This retries up to 5 times with delays of 2s, 4s, 8s, 16s, and 32s. Only transient errors trigger retries — BadRequestError or AuthenticationError fail immediately since retrying would not help.
OpenAI returns rate limit information in response headers. Use this to implement proactive throttling:
from openai import OpenAI
client = OpenAI()
response = client.chat.completions.with_raw_response.create(
model="gpt-4o",
messages=[{"role": "user", "content": "Hello"}],
)
# Access rate limit headers
print(f"Requests remaining: {response.headers.get('x-ratelimit-remaining-requests')}")
print(f"Tokens remaining: {response.headers.get('x-ratelimit-remaining-tokens')}")
print(f"Resets at: {response.headers.get('x-ratelimit-reset-requests')}")
# Parse the actual response
completion = response.parse()
print(completion.choices[0].message.content)
When errors persist, a circuit breaker stops sending requests entirely to avoid wasting resources and hitting rate limits harder:
import time
from openai import OpenAI, APIError
class CircuitBreaker:
def __init__(self, failure_threshold: int = 5, reset_timeout: int = 60):
self.failure_threshold = failure_threshold
self.reset_timeout = reset_timeout
self.failure_count = 0
self.last_failure_time = 0.0
self.state = "closed" # closed = normal, open = blocking
def call(self, func, *args, **kwargs):
if self.state == "open":
if time.time() - self.last_failure_time > self.reset_timeout:
self.state = "half-open"
else:
raise Exception("Circuit breaker is open. Service unavailable.")
try:
result = func(*args, **kwargs)
if self.state == "half-open":
self.state = "closed"
self.failure_count = 0
return result
except APIError:
self.failure_count += 1
self.last_failure_time = time.time()
if self.failure_count >= self.failure_threshold:
self.state = "open"
raise
client = OpenAI()
breaker = CircuitBreaker(failure_threshold=3, reset_timeout=30)
def safe_completion(prompt: str) -> str:
return breaker.call(
lambda: client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}],
).choices[0].message.content
)
When your primary model is unavailable, fall back to an alternative:
Still reading? Stop comparing — try CallSphere live.
CallSphere ships complete AI voice agents per industry — 14 tools for healthcare, 10 agents for real estate, 4 specialists for salons. See how it actually handles a call before you book a demo.
from openai import OpenAI, RateLimitError, InternalServerError
client = OpenAI()
FALLBACK_CHAIN = ["gpt-4o", "gpt-4o-mini", "gpt-3.5-turbo"]
def resilient_completion(messages: list[dict]) -> str:
for model in FALLBACK_CHAIN:
try:
response = client.chat.completions.create(
model=model,
messages=messages,
)
return response.choices[0].message.content
except (RateLimitError, InternalServerError) as e:
print(f"{model} failed: {e}. Trying next model...")
continue
raise Exception("All models in fallback chain failed.")
Start with 2 seconds and use exponential backoff. The retry-after header in the response tells you exactly how long to wait. If present, respect that value instead of guessing.
No. A 400 error means your request is malformed. Retrying the same request will produce the same error. Fix the request payload instead.
OpenAI enforces both. Request rate limits cap how many API calls you make per minute. Token rate limits cap total tokens (input + output) per minute. You can hit either limit independently.
#OpenAI #ErrorHandling #RateLimits #Resilience #Python #AgenticAI #LearnAI #AIEngineering

Written by
Sagar Shankaran· Founder, CallSphere
LinkedInSagar Shankaran is the founder of CallSphere, where he builds production AI voice and chat agents deployed across healthcare, hospitality, real estate, and home services. He writes about agentic AI, LLM engineering, and shipping voice agents that handle real calls in production.
See how AI voice agents work for your industry. Live demo available -- no signup required.
How resilient small businesses in Kyiv, Lviv and across Ukraine use CallSphere AI voice and chat agents to answer every call 24/7 in Ukrainian, Russian and English, book appointments and recover lost revenue.
OpenAI's Frontier platform makes model-native orchestration the default. What that means for agent builders, voice/chat buyers, and the build-vs-buy decision.
The 2026 desktop AI agent landscape — ServiceNow Project Arc, Anthropic Claude offerings, OpenAI agents, and Google Mariner. A buyer's map.
May 2026's biggest agent-architecture shift: planning, tool selection, and self-correction move inside the model. Framework code shrinks. Here is what changes.
A three-way comparison of Gemini Enterprise, Anthropic managed agents and OpenAI Frontier Platform after Cloud Next 2026 — strengths, gaps, buyer fit.
Anthropic's May 2026 push positions Claude as a vertical platform for financial services. The strategic positioning versus OpenAI and Google.
© 2026 CallSphere Inc. All rights reserved.
Made within San Francisco
Watch how CallSphere handles real customer calls, schedules appointments, and processes payments — live.