diff --git a/src/claude_agent_sdk/_internal/query.py b/src/claude_agent_sdk/_internal/query.py index 7a4f8a447..af97a5168 100644 --- a/src/claude_agent_sdk/_internal/query.py +++ b/src/claude_agent_sdk/_internal/query.py @@ -303,8 +303,16 @@ async def _read_messages(self) -> None: self._first_result_event.set() if message.get("is_error"): errors = message.get("errors") or [] - self._last_error_result_text = "; ".join(errors) or str( - message.get("subtype", "unknown error") + # Prefer the joined errors[] list, then the + # human-readable "result" field, before falling back to + # the subtype. For some API-level errors (e.g. + # model_not_found) errors[] is empty and subtype is + # "success", which would otherwise produce the + # contradictory "returned an error result: success". + self._last_error_result_text = ( + "; ".join(errors) + or message.get("result") + or str(message.get("subtype", "unknown error")) ) else: self._last_error_result_text = None diff --git a/tests/test_query.py b/tests/test_query.py index 3ae65093d..b946c3950 100644 --- a/tests/test_query.py +++ b/tests/test_query.py @@ -1059,6 +1059,44 @@ async def _test(): anyio.run(_test) + def test_process_error_empty_errors_uses_result_field_not_subtype(self): + """Regression for #1031: when errors[] is empty but the result carries + a human-readable "result" field (e.g. a model_not_found 404 where the + protocol-level subtype is "success"), surface the result text instead + of the misleading "Claude Code returned an error result: success".""" + + async def _test(): + transport = self._make_transport_then_raise( + messages=[ + self._error_result( + subtype="success", + errors=[], + result=( + "There's an issue with the selected model " + "(nonexistent-model). It may not exist or you may " + "not have access to it." + ), + api_error_status=404, + ) + ], + exc=ProcessError( + "Command failed with exit code 1", exit_code=1, stderr="" + ), + ) + q = Query(transport=transport, is_streaming_mode=True) + await q.start() + + with pytest.raises( + Exception, + match=r"Claude Code returned an error result: There's an issue " + r"with the selected model \(nonexistent-model\)\.", + ): + async for _ in q.receive_messages(): + pass + await q.close() + + anyio.run(_test) + def test_process_error_without_result_keeps_original_message(self): async def _test(): transport = self._make_transport_then_raise(