Summary
The thenvoi_rest SDK throws a confusing JSONDecodeError when the API returns a 429 response with an empty body. While the SDK does eventually raise the correct ApiError, the intermediate JSONDecodeError traceback is displayed due to Python's exception chaining, creating noisy output.
Environment
- Python 3.12
- thenvoi-sdk-python (latest)
- Server returning 429 from AWS ALB with empty body (
Content-Length: 0)
Actual Behavior
Traceback (most recent call last):
File ".../thenvoi_rest/agent_api/raw_client.py", line 2987, in get_agent_me
_response_json = _response.json()
...
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
...
thenvoi_rest.core.api_error.ApiError: status_code: 429, body:
Expected Behavior
A clean ApiError with no intermediate exception traceback.
Root Cause
In raw_client.py (lines 2955-2990), the code pattern is:
try:
if 200 <= _response.status_code < 300:
return parse_response(_response.json())
if _response.status_code == 401:
raise UnauthorizedError(body=_response.json())
if _response.status_code == 403:
raise ForbiddenError(body=_response.json())
_response_json = _response.json() # <-- Fails here for 429 with empty body
except JSONDecodeError:
raise ApiError(...) # Exception chaining shows both tracebacks
- 429 doesn't match the explicit handlers, so falls through to JSON parsing
- Empty body causes
JSONDecodeError
- Python's exception chaining displays both tracebacks
Note: thenvoi_rest is auto-generated by Fern, so fixes must go in Fern templates.
Proposed Fix
Option 1: Fern template fix - Add from None (Recommended)
except JSONDecodeError:
raise ApiError(...) from None # Suppress chained exception
Option 2: Early exit for error responses
if _response.status_code >= 400:
try:
body = _response.json()
except JSONDecodeError:
body = _response.text
raise ApiError(status_code=..., body=body)
Impact
- Severity: Low (functional behavior is correct, UX is poor)
- Scope: All 32 API methods in
raw_client.py follow this pattern
Summary
The
thenvoi_restSDK throws a confusingJSONDecodeErrorwhen the API returns a 429 response with an empty body. While the SDK does eventually raise the correctApiError, the intermediateJSONDecodeErrortraceback is displayed due to Python's exception chaining, creating noisy output.Environment
Content-Length: 0)Actual Behavior
Expected Behavior
A clean
ApiErrorwith no intermediate exception traceback.Root Cause
In
raw_client.py(lines 2955-2990), the code pattern is:JSONDecodeErrorNote:
thenvoi_restis auto-generated by Fern, so fixes must go in Fern templates.Proposed Fix
Option 1: Fern template fix - Add
from None(Recommended)Option 2: Early exit for error responses
Impact
raw_client.pyfollow this pattern