Skip to content

Commit 8088254

Browse files
Improve extraction of list-based API error messages
Co-authored-by: Shri Sukhani <shrisukhani@users.noreply.github.com>
1 parent 8b0fbfd commit 8088254

File tree

2 files changed

+31
-5
lines changed

2 files changed

+31
-5
lines changed

hyperbrowser/transport/error_utils.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,22 @@ def _stringify_error_value(value: Any) -> str:
88
if isinstance(value, str):
99
return value
1010
if isinstance(value, dict):
11-
for key in ("message", "error", "detail"):
11+
for key in ("message", "error", "detail", "msg"):
1212
nested_value = value.get(key)
1313
if nested_value is not None:
1414
return _stringify_error_value(nested_value)
15+
if isinstance(value, (list, tuple)):
16+
collected_messages = [
17+
item_message
18+
for item_message in (_stringify_error_value(item) for item in value)
19+
if item_message
20+
]
21+
if collected_messages:
22+
return (
23+
collected_messages[0]
24+
if len(collected_messages) == 1
25+
else "; ".join(collected_messages)
26+
)
1527
try:
1628
return json.dumps(value, sort_keys=True)
1729
except TypeError:

tests/test_transport_response_handling.py

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -222,22 +222,36 @@ def test_sync_handle_response_with_dict_without_message_keys_stringifies_payload
222222
transport.close()
223223

224224

225-
def test_async_handle_response_with_non_dict_json_stringifies_payload():
225+
def test_async_handle_response_with_non_dict_json_uses_first_item_payload():
226226
async def run() -> None:
227227
transport = AsyncTransport(api_key="test-key")
228228
try:
229229
response = _build_response(500, '[{"code":"UPSTREAM_FAILURE"}]')
230230

231-
with pytest.raises(
232-
HyperbrowserError, match='\\[\\{"code": "UPSTREAM_FAILURE"\\}\\]'
233-
):
231+
with pytest.raises(HyperbrowserError, match='"code": "UPSTREAM_FAILURE"'):
234232
await transport._handle_response(response)
235233
finally:
236234
await transport.close()
237235

238236
asyncio.run(run())
239237

240238

239+
def test_sync_handle_response_with_validation_error_detail_list_uses_msg_values():
240+
transport = SyncTransport(api_key="test-key")
241+
try:
242+
response = _build_response(
243+
422,
244+
'{"detail":[{"msg":"field required"},{"msg":"invalid email address"}]}',
245+
)
246+
247+
with pytest.raises(
248+
HyperbrowserError, match="field required; invalid email address"
249+
):
250+
transport._handle_response(response)
251+
finally:
252+
transport.close()
253+
254+
241255
def test_sync_transport_post_wraps_request_errors_with_url_context():
242256
transport = SyncTransport(api_key="test-key")
243257
original_post = transport.client.post

0 commit comments

Comments
 (0)