Skip to content

Misleading error message: 'Claude Code returned an error result: success' when errors[] is empty #1031

@dumko2001

Description

@dumko2001

Bug description

When the Claude Code CLI exits with code 1 and emits a result message where is_error=true but errors is an empty list (e.g. on a model_not_found 404), the SDK raises an exception with the message:

Claude Code returned an error result: success

The word "success" is the subtype field of the result JSON, used as a fallback label. It is not an error description — it just means the session terminated cleanly at the protocol level. The actual human-readable error sits in the result field of the same JSON object and is silently discarded.

Steps to reproduce

  1. Run the CLI with a non-existent model:
claude --output-format=stream-json --print --model nonexistent-model "hello"

Observe the last stdout line before exit 1:

{
  "type": "result",
  "subtype": "success",
  "is_error": true,
  "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
}
  1. Use the SDK to invoke the same — the raised exception message will be "Claude Code returned an error result: success" instead of the actual model error.

Root cause

query.py:304-307:

if message.get("is_error"):
    errors = message.get("errors") or []
    self._last_error_result_text = "; ".join(errors) or str(
        message.get("subtype", "unknown error")   # ← "success" when errors=[]
    )

"; ".join([]) is "" (falsy), so it falls through to message.get("subtype"). For model_not_found and likely other API-level errors, subtype is "success" (indicating a clean protocol-level exit), producing the contradictory label.

The human-readable error is in message.get("result"), which is never consulted.

Expected behaviour

The exception should surface the actual error text:

Claude Code returned an error result: There's an issue with the selected model (nonexistent-model). It may not exist or you may not have access to it.

Suggested fix

if message.get("is_error"):
    errors = message.get("errors") or []
    self._last_error_result_text = (
        "; ".join(errors)
        or message.get("result")           # ← check result field before subtype
        or str(message.get("subtype", "unknown error"))
    )

Version

  • claude-agent-sdk==0.2.97
  • Observed via claude-code v2.1.173 with --output-format=stream-json

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workinggood first issueGood for newcomers

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions