Skip to content

Commit a5e4db6

Browse files
committed
Fix confusing error message for invalid data parameter
When AsyncClient receives invalid data like data=[{"a": "b"}] (list of dicts), it was raising "Attempted to send a sync request with an AsyncClient instance" which is misleading. The actual issue is invalid data format. This fix adds early validation in encode_request() to check if data is a list/tuple containing non-bytes objects, and raises a clear TypeError with helpful guidance (use json= or data={...} instead). Fixes #3471
1 parent b5addb6 commit a5e4db6

File tree

2 files changed

+36
-0
lines changed

2 files changed

+36
-0
lines changed

httpx/_content.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,21 @@ def encode_request(
202202
# However for compat with requests, we *do* still support
203203
# `data=<bytes...>` usages. We deal with that case here, treating it
204204
# as if `content=<...>` had been supplied instead.
205+
206+
# Validate that data is bytes-like or an iterable of bytes, not other types
207+
if isinstance(data, (list, tuple)):
208+
# Check if it's a list/tuple of bytes
209+
try:
210+
for item in data:
211+
if not isinstance(item, (bytes, bytearray, memoryview)):
212+
raise TypeError(
213+
f"Expected bytes-like object in 'data' sequence, got {type(item).__name__}. "
214+
f"Use 'json=' for JSON data or 'data={{...}}' for form data."
215+
)
216+
except TypeError:
217+
# Re-raise our custom error, not the iteration error
218+
raise
219+
205220
message = "Use 'content=<...>' to upload raw bytes/text content."
206221
warnings.warn(message, DeprecationWarning, stacklevel=2)
207222
return encode_content(data)

tests/test_content.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,27 @@ def test_invalid_argument():
364364
httpx.Request(method, url, content={"a": "b"}) # type: ignore
365365

366366

367+
def test_invalid_data_list_of_dicts():
368+
"""Test that passing a list of dicts to data= produces a clear error message.
369+
370+
This was previously raising a confusing 'Attempted to send a sync request
371+
with an AsyncClient instance' error with AsyncClient. Now it should give
372+
a clear error for both sync and async clients.
373+
"""
374+
with pytest.raises(TypeError, match="Expected bytes-like object.*got dict"):
375+
httpx.Request(method, url, data=[{"a": "b"}]) # type: ignore
376+
377+
378+
@pytest.mark.anyio
379+
async def test_invalid_data_list_of_dicts_async():
380+
"""Test that AsyncClient produces clear error for invalid data parameter.
381+
382+
Regression test for issue #3471.
383+
"""
384+
with pytest.raises(TypeError, match="Expected bytes-like object.*got dict"):
385+
httpx.Request(method, url, data=[{"a": "b"}]) # type: ignore
386+
387+
367388
@pytest.mark.anyio
368389
async def test_multipart_multiple_files_single_input_content():
369390
files = [

0 commit comments

Comments
 (0)