From 969e9b457d105b02df415a795ba5459dba354bb7 Mon Sep 17 00:00:00 2001 From: RoomWithOutRoof <166608075+Jah-yee@users.noreply.github.com> Date: Thu, 19 Mar 2026 17:15:31 +0800 Subject: [PATCH] fix: map SSE error types to correct HTTP status codes --- src/anthropic/_streaming.py | 48 +++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/src/anthropic/_streaming.py b/src/anthropic/_streaming.py index fc6943ee..1a75ec41 100644 --- a/src/anthropic/_streaming.py +++ b/src/anthropic/_streaming.py @@ -19,6 +19,28 @@ _T = TypeVar("_T") +# Mapping from SSE error type to HTTP status code +# See: https://docs.anthropic.com/en/api/error-codes +_SSE_ERROR_TYPE_TO_STATUS = { + "overloaded_error": 529, + "rate_limit_error": 429, + "api_error": 500, + "internal_server_error": 500, + "authentication_error": 401, + "invalid_request_error": 400, + "not_found_error": 404, +} + + +def _get_status_code_from_sse_error(body: dict, default_status_code: int) -> int: + """Extract the appropriate HTTP status code from an SSE error body.""" + if isinstance(body, dict) and "error" in body: + error_type = body["error"].get("type") + if error_type in _SSE_ERROR_TYPE_TO_STATUS: + return _SSE_ERROR_TYPE_TO_STATUS[error_type] + return default_status_code + + class _SyncStreamMeta(abc.ABCMeta): @@ -111,10 +133,21 @@ def __stream__(self) -> Iterator[_T]: except Exception: err_msg = sse.data or f"Error code: {response.status_code}" + # Create a mock response with the correct status code based on SSE error type + status_code = _get_status_code_from_sse_error( + body if isinstance(body, dict) else {}, + response.status_code + ) + error_response = httpx.Response( + status_code=status_code, + content=response.content, + headers=response.headers, + request=response.request, + ) raise self._client._make_status_error( err_msg, body=body, - response=self.response, + response=error_response, ) finally: # Ensure the response is closed even if the consumer doesn't read all data @@ -231,10 +264,21 @@ async def __stream__(self) -> AsyncIterator[_T]: except Exception: err_msg = sse.data or f"Error code: {response.status_code}" + # Create a mock response with the correct status code based on SSE error type + status_code = _get_status_code_from_sse_error( + body if isinstance(body, dict) else {}, + response.status_code + ) + error_response = httpx.Response( + status_code=status_code, + content=response.content, + headers=response.headers, + request=response.request, + ) raise self._client._make_status_error( err_msg, body=body, - response=self.response, + response=error_response, ) finally: # Ensure the response is closed even if the consumer doesn't read all data