-
Notifications
You must be signed in to change notification settings - Fork 22
Handle API Status errors 499 differently #132
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
47ae16d
70c8be7
c38b939
a0fe49e
d665364
389529a
14f2480
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -18,6 +18,8 @@ | |||||||||||||
| # from agents.run import DEFAULT_MAX_TURNS # XXX: this is 10, we need more than that | ||||||||||||||
| from agents.exceptions import AgentsException, MaxTurnsExceeded | ||||||||||||||
| from agents.extensions.handoff_prompt import prompt_with_handoff_instructions | ||||||||||||||
| from agents import Tool, RunContextWrapper, TContext, Agent | ||||||||||||||
| from openai import BadRequestError, APITimeoutError, RateLimitError, APIStatusError | ||||||||||||||
| from agents.mcp import MCPServerSse, MCPServerStdio, MCPServerStreamableHttp, create_static_tool_filter | ||||||||||||||
| from dotenv import find_dotenv, load_dotenv | ||||||||||||||
| from openai import APITimeoutError, BadRequestError, RateLimitError | ||||||||||||||
|
|
@@ -350,7 +352,16 @@ async def _run_streamed(): | |||||||||||||
| return | ||||||||||||||
| except APITimeoutError: | ||||||||||||||
| if not max_retry: | ||||||||||||||
| logging.exception("Max retries for APITimeoutError reached") | ||||||||||||||
| logging.error(f"Max API retries reached") | ||||||||||||||
| raise | ||||||||||||||
| max_retry -= 1 | ||||||||||||||
| except APIStatusError as e: | ||||||||||||||
| # Retry transient “client closed request / upstream cancelled” style errors | ||||||||||||||
| if getattr(e, "status_code", None) != 499: | ||||||||||||||
| raise # propagate non-499 errors | ||||||||||||||
| # 499: retry | ||||||||||||||
| if not max_retry: | ||||||||||||||
| logging.error(f"Max API retries reached") | ||||||||||||||
| raise | ||||||||||||||
| max_retry -= 1 | ||||||||||||||
|
Comment on lines
+358
to
366
|
||||||||||||||
| except RateLimitError: | ||||||||||||||
|
|
@@ -377,8 +388,15 @@ async def _run_streamed(): | |||||||||||||
| await render_model_output(f"** 🤖❗ Request Error: {e}\n", async_task=async_task, task_id=task_id) | ||||||||||||||
| logging.exception("Bad Request") | ||||||||||||||
| except APITimeoutError as e: | ||||||||||||||
| await render_model_output(f"** 🤖❗ Timeout Error: {e}\n", async_task=async_task, task_id=task_id) | ||||||||||||||
| logging.exception("Bad Request") | ||||||||||||||
| await render_model_output(f"** 🤖❗ Timeout Error: {e}\n", | ||||||||||||||
| async_task=async_task, | ||||||||||||||
| task_id=task_id) | ||||||||||||||
| logging.error(f"Bad Request: {e}") | ||||||||||||||
|
||||||||||||||
| logging.error(f"Bad Request: {e}") | |
| logging.exception("Timeout Error") |
Copilot
AI
Jan 20, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The APIStatusError exception handler is placed before the more specific exception types (BadRequestError, APITimeoutError, RateLimitError) in the exception hierarchy. Since these specific exceptions inherit from APIStatusError, this catch block will intercept them before they reach their intended handlers above (lines 372-381). The APIStatusError handler should be moved to the end of the exception chain, after all the more specific handlers.
Copilot
AI
Feb 9, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logging.error(f"API Status Error: Status={e.status_code}, Response={e.response}") logs the full response object, which can be very large and may include sensitive payloads. Prefer logging a minimal, stable subset (e.g., status_code + request id / error type/message) to avoid leaking content and to keep logs bounded.
| logging.error(f"API Status Error: Status={e.status_code}, Response={e.response}") | |
| logging.error( | |
| "API Status Error: status=%s, message=%s", | |
| getattr(e, "status_code", "unknown"), | |
| getattr(e, "message", str(e)), | |
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Duplicate imports were introduced:
Agent/RunContextWrapper/TContext/Toolare imported twice (line 15 and 21) and OpenAI exception classes are imported twice (line 22 and 25). Consolidate into a single import per module to avoid lint failures and keep imports maintainable.