-
Notifications
You must be signed in to change notification settings - Fork 6
Description
Hello,
When migrating to v4, we are experiencing issues when receiving responses with HTTP status code 204: brevo-python library tries to decodes JSON from a body which has... no content (as expected with status code 204). This leads to an unexpected ApiError.
The following minimal example reproduces the issue. Contact is well created then updated on Brevo side (CRM shows that the value for attribute USER_ID is 456 after execution), so I guess that no exception should be raised.
import time
import brevo
API_KEY = "xkeysib-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxx"
email = f"bug+{int(time.time())}@example.com"
client = brevo.Brevo(api_key=API_KEY)
response = client.contacts.create_contact(email=email, attributes={"USER_ID": 123}, update_enabled=True)
print(response)
response = client.contacts.create_contact(email=email, attributes={"USER_ID": 456}, update_enabled=True)
print(response)Here is the full output with stacktrace when running the script above:
$ python /home/patrick/tmp/bug.py
id=207952
Traceback (most recent call last):
File "/home/patrick/.cache/pypoetry/virtualenvs/pcapi-KcUJqeq--py3.13/lib/python3.13/site-packages/brevo/contacts/raw_client.py", line 260, in create_contact
object_=_response.json(),
~~~~~~~~~~~~~~^^
File "/home/patrick/.cache/pypoetry/virtualenvs/pcapi-KcUJqeq--py3.13/lib/python3.13/site-packages/httpx/_models.py", line 832, in json
return jsonlib.loads(self.content, **kwargs)
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.13/json/__init__.py", line 352, in loads
return _default_decoder.decode(s)
~~~~~~~~~~~~~~~~~~~~~~~^^^
File "/usr/lib/python3.13/json/decoder.py", line 345, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.13/json/decoder.py", line 363, in raw_decode
raise JSONDecodeError("Expecting value", s, err.value) from None
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):
File "/home/patrick/tmp/bug.py", line 12, in <module>
response = client.contacts.create_contact(email=email, attributes={"USER_ID": 456}, update_enabled=True)
File "/home/patrick/.cache/pypoetry/virtualenvs/pcapi-KcUJqeq--py3.13/lib/python3.13/site-packages/brevo/contacts/client.py", line 203, in create_contact
_response = self._raw_client.create_contact(
attributes=attributes,
...<7 lines>...
request_options=request_options,
)
File "/home/patrick/.cache/pypoetry/virtualenvs/pcapi-KcUJqeq--py3.13/lib/python3.13/site-packages/brevo/contacts/raw_client.py", line 288, in create_contact
raise ApiError(status_code=_response.status_code, headers=dict(_response.headers), body=_response.text)
brevo.core.api_error.ApiError: headers: {'date': 'Fri, 27 Mar 2026 11:21:54 GMT', 'content-type': 'text/plain; charset=utf-8', 'connection': 'keep-alive', 'cf-ray': '9e2e03a08d5bef8d-WAW', 'x-envoy-upstream-service-time': '197', 'access-control-allow-credentials': 'true', 'sib-request-id': '30e941c6-391e-976e-aa8a-3299bbdb07d1', 'access-control-allow-origin': '*', 'access-control-allow-headers': '*', 'access-control-allow-methods': 'PUT, POST, GET, DELETE, PATCH, OPTIONS', 'x-sib-ratelimit-limit': '20', 'x-sib-ratelimit-remaining': '19', 'x-sib-ratelimit-reset': '1', 'cf-cache-status': 'DYNAMIC', 'server': 'cloudflare'}, status_code: 204, body:
Case of status code 204 No Content should probably be excluded from the block which reads content as json here: https://github.com/getbrevo/brevo-python/blob/v4.0.8/src/brevo/contacts/raw_client.py#L255 (and probably also in other modules).
My environment:
- python 3.13
- poetry 2.2.1
- brevo-python 4.0.8
- httpx 0.28.1