BerriAI/litellm · error · MaskedHTTPStatusError
_body (masked response body)
Error message
_body (masked response body)
What it means
When a sync streaming HTTP call in litellm's HTTPHandler gets a non-2xx response, litellm reads the body (with a bounded timeout), masks sensitive info such as keys in the URL/body via mask_sensitive_info, and raises MaskedHTTPStatusError. The message is the masked response body of the failed upstream request.
Source
Thrown at litellm/llms/custom_httpx/http_handler.py:460
except Exception:
response.close()
return b""
return response.read()
except Exception:
return b""
def _raise_masked_sync_error(e: httpx.HTTPStatusError, stream: bool) -> None:
"""Raise a MaskedHTTPStatusError for sync HTTP handlers."""
if stream:
try:
_body: Final = mask_sensitive_info(
_safe_read_response(
e.response,
timeout=_STREAMING_ERROR_BODY_READ_TIMEOUT_SECONDS,
)
)
raise MaskedHTTPStatusError(e, message=_body, text=_body) from None
finally:
try:
e.response.close()
except Exception:
pass
_text: Final = mask_sensitive_info(_safe_get_response_text(e.response))
raise MaskedHTTPStatusError(e, message=_text, text=_text) from None
async def _raise_masked_async_error(e: httpx.HTTPStatusError, stream: bool) -> None:
"""Raise a MaskedHTTPStatusError for async HTTP handlers."""
if stream:
try:
_body: Final = mask_sensitive_info(
await _safe_aread_response(
e.response,
timeout=_STREAMING_ERROR_BODY_READ_TIMEOUT_SECONDS,
)View on GitHub (pinned to 6c2dcb801b)
Solutions
- Catch httpx.HTTPStatusError (MaskedHTTPStatusError subclasses it) and inspect .response.status_code
- Fix the root cause per status: 401/403 -> API key; 404 -> model name/api_base; 429 -> backoff or higher limits; 5xx -> provider health
- If behind a proxy, verify it forwards auth headers and returns the provider's real status
Example fix
# before
resp = client.post(url, json=payload) # raises on non-2xx
# after
import httpx
try:
resp = client.post(url, json=payload)
except httpx.HTTPStatusError as e: # includes MaskedHTTPStatusError
if e.response.status_code == 429:
await asyncio.sleep(backoff)
else:
raise Defensive patterns
Strategy: retry
Try / catch
import httpx
from litellm.llms.custom_httpx.http_handler import MaskedHTTPStatusError
try:
stream = client.stream("POST", url, ...)
except MaskedHTTPStatusError as e:
if e.response.status_code == 429:
retry_with_backoff()
raise Prevention
- Pre-check credentials and model names before opening streams
- Treat 429/5xx as retryable and 4xx (except 429) as configuration bugs
When it happens
Trigger: Sync streaming completions where the upstream returns 4xx/5xx — invalid API key (401), model not found, context length exceeded, rate limits (429), or upstream 5xx — during httpx streaming.
Common situations: Wrong or expired API keys; hitting provider rate limits mid-stream; requesting a model name the provider does not serve; proxy servers returning HTML/JSON error pages. Masking means the exception text is safe to log.
Related errors
- _text (masked response text)
- Braintrust API error: {e.response.text}
- Failed to connect to Braintrust API: {str(e)}
- Failed to transform Braintrust response: {str(e)}
- Error apply_db_fixes: {str(e)}
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/a2633e140bbc1efd.
Report an issue: GitHub.