rohitg00/ai-engineering-from-scratch · error · EventStreamError

idle status needs a supported stop_reason

Error message

idle status needs a supported stop_reason

What it means

Raised in consume_managed_events when a session.status_idle event arrives whose stop_reason is not a dict with type 'requires_action' or 'end_turn'. Idle is a terminal state in this reducer, so an unknown or missing stop reason would leave the summary in an undefined terminal condition.

Solutions

  1. Emit stop_reason as {'type': 'requires_action'|'end_turn', ...} on every status_idle event
  2. Fix stream producers that omit stop_reason when the session goes idle
  3. Extend the accepted stop_reason types here and in the summary contract together if a new terminal state is added

When it happens

Trigger: Thrown at certifications/claude/lessons/12-claude-agent-sdk-and-hooks/code/main.py:99 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of rohitg00/ai-engineering-from-scratch@39ea8a1c6d (2026-08-26). Data as JSON: /api/errors/fb7604a0d2b0dae2. Report an issue: GitHub.

Appendix: source

Thrown at certifications/claude/lessons/12-claude-agent-sdk-and-hooks/code/main.py:99

            messages.append(
                "".join(
                    str(block.get("text", ""))
                    for block in content
                    if isinstance(block, dict) and block.get("type") == "text"
                )
            )
        elif event_type in {"agent.custom_tool_use", "agent.tool_use", "agent.mcp_tool_use"}:
            actionable.add(event_id)
        elif event_type in {"user.custom_tool_result", "user.tool_confirmation"}:
            reference = event.get("custom_tool_use_id") or event.get("tool_use_id")
            if not isinstance(reference, str) or reference not in actionable:
                raise EventStreamError("tool result or confirmation must reference a known action")
            pending.discard(reference)
        elif event_type == "session.status_idle":
            status = "idle"
            reason = event.get("stop_reason")
            if not isinstance(reason, dict) or reason.get("type") not in {"requires_action", "end_turn"}:
                raise EventStreamError("idle status needs a supported stop_reason")
            stop_reason = reason["type"]
            if stop_reason == "requires_action":
                event_ids = reason.get("event_ids")
                if not isinstance(event_ids, list) or not event_ids or not all(
                    isinstance(item, str) and item in actionable for item in event_ids
                ):
                    raise EventStreamError("requires_action must reference known actionable event IDs")
                pending = set(event_ids)
            else:
                pending.clear()
        elif event_type == "session.status_terminated":
            status = "terminated"
            stop_reason = "terminated"
            pending.clear()
        elif event_type == "session.error":
            raise EventStreamError("session emitted an error event")

    complete = status == "terminated" or (status == "idle" and stop_reason == "end_turn")

View on GitHub (pinned to 39ea8a1c6d)