In short: when a framework agent fails, the SDK prints None instead of the reason — even though the server recorded a perfectly good one. Every such failure costs a manual walk of the server API to diagnose.
File: src/conductor/ai/agents/runtime/runtime.py
Symptom
$ CONDUCTOR_AGENT_LLM_MODEL=anthropic/claude-sonnet-4-6 python examples/agents/93_openai_runner_hello_world.py
Framework agent 'Assistant' execution FAILED
None
No reason, no task name, nothing actionable. Diagnosing it means walking the server API by hand:
curl -s localhost:8080/api/agent/executions?size=20
curl -s "localhost:8080/api/workflow/<executionId>?includeTasks=true" # find FAILED tasks, read reasonForIncompletion
Cause
_run_framework() reports:
error=status.reason if raw_status in ("FAILED", "TERMINATED") else None
For these failures status.reason is empty, so the result is None.
The reason was available all along, at both levels of the execution:
- the workflow's own
reasonForIncompletion:
Task 41830611-7c25-4d51-a36f-50e324e59239 failed with status: FAILED and reason:
'Task execution failed: OpenAI Responses API call failed: Responses API failed with status 401 ...'
- the failed task's
reasonForIncompletion (Assistant_llm), carrying the same text.
There is also an existing helper that already does this. _extract_failed_task_reason(wf) reads the first FAILED task's reasonForIncompletion and returns Task '<ref>' failed: <reason>. It is called by run() (line ~2534) and _run_by_name() (line ~2623) — which is why native-agent failures report properly, e.g. 54_software_bug_assistant prints:
ERROR: Task 'software_assistant_54_list_mcp_0' failed: Failed to list MCP tools ... HTTP 400
_run_framework() never calls it.
Fix
When status.reason is empty, fall back to the workflow's reasonForIncompletion, or call _extract_failed_task_reason as run() does. Either is sufficient.
Verify
Start the server without OPENAI_API_KEY, run 93 — it should name the failing task and its reason instead of printing None.
Note — possible second gap, unconfirmed
59_coding_agent goes through run() yet also reported no reason, while its server-side SUB_WORKFLOW task did carry one (Anthropic Messages API failed with status 404). _extract_failed_task_reason only inspects the top-level workflow's tasks, so failures inside a sub-workflow may need the same treatment. Worth checking while fixing this.
In short: when a framework agent fails, the SDK prints
Noneinstead of the reason — even though the server recorded a perfectly good one. Every such failure costs a manual walk of the server API to diagnose.File:
src/conductor/ai/agents/runtime/runtime.pySymptom
No reason, no task name, nothing actionable. Diagnosing it means walking the server API by hand:
Cause
_run_framework()reports:For these failures
status.reasonis empty, so the result isNone.The reason was available all along, at both levels of the execution:
reasonForIncompletion:reasonForIncompletion(Assistant_llm), carrying the same text.There is also an existing helper that already does this.
_extract_failed_task_reason(wf)reads the first FAILED task'sreasonForIncompletionand returnsTask '<ref>' failed: <reason>. It is called byrun()(line ~2534) and_run_by_name()(line ~2623) — which is why native-agent failures report properly, e.g.54_software_bug_assistantprints:_run_framework()never calls it.Fix
When
status.reasonis empty, fall back to the workflow'sreasonForIncompletion, or call_extract_failed_task_reasonasrun()does. Either is sufficient.Verify
Start the server without
OPENAI_API_KEY, run93— it should name the failing task and its reason instead of printingNone.Note — possible second gap, unconfirmed
59_coding_agentgoes throughrun()yet also reported no reason, while its server-side SUB_WORKFLOW task did carry one (Anthropic Messages API failed with status 404)._extract_failed_task_reasononly inspects the top-level workflow's tasks, so failures inside a sub-workflow may need the same treatment. Worth checking while fixing this.