datawhalechina/hello-agents · error · WorkflowExecutionError
{stage}失败:工具结果必须是 JSON 对象
Error message
{stage}失败:工具结果必须是 JSON 对象 What it means
Raised by _run_tool when the tool's JSON parses successfully but is not an object — e.g. a list, string, number, or null. The protocol requires a JSON object at top level because the next step reads payload['ok'] and payload['message']. So '[]', '"ok"', or 'null' all pass json.loads then fail this check.
Source
Thrown at Co-creation-projects/zenith191-RequirementClarifierAgent/src/workflow.py:155
def _run_tool(
self, name: str, parameters: dict[str, object], stage: str
) -> dict[str, object]:
"""通过官方 ToolRegistry 获取工具并解析其字符串协议。"""
tool = self.tool_registry.get_tool(name)
if tool is None:
raise WorkflowExecutionError(f"{stage}失败:工具 {name} 未注册")
try:
raw_result = tool.run(parameters)
except Exception as exc:
raise WorkflowExecutionError(f"{stage}失败:工具执行异常:{exc}") from exc
try:
payload = json.loads(raw_result)
except (TypeError, ValueError) as exc:
raise WorkflowExecutionError(f"{stage}失败:工具返回的不是有效 JSON") from exc
if not isinstance(payload, dict):
raise WorkflowExecutionError(f"{stage}失败:工具结果必须是 JSON 对象")
if not payload.get("ok"):
raise WorkflowExecutionError(
f"{stage}失败:{payload.get('message', '未知工具错误')}"
)
return payload
def _clear_agent_histories(self) -> None:
"""避免多次运行时把上一条需求带入下一条需求。"""
for agent in (
self.team.analyst,
self.team.architect,
self.team.reviewer,
self.team.synthesizer,
):
clear_history = getattr(agent, "clear_history", None)
if callable(clear_history):
clear_history()View on GitHub (pinned to 606a07d341)
Solutions
- Wrap non-object output: return json.dumps({"ok": True, "results": [...]}) instead of a bare list.
- Check for accidental double encoding — one json.dumps only.
- Audit each custom tool with: payload = json.loads(t.run(p)); assert isinstance(payload, dict) and 'ok' in payload.
Example fix
# before
def run(self, params):
return json.dumps(search(params["q"])) # list
# after
def run(self, params):
return json.dumps({"ok": True, "results": search(params["q"])}) Defensive patterns
Strategy: type-guard
Validate before calling
import json
def tool_result_is_object(tool, sample_params) -> bool:
payload = json.loads(tool.run(sample_params))
return isinstance(payload, dict)
# enforce at registration time
for t in tools:
assert tool_result_is_object(t, t.sample_params), t.name Type guard
import json
def decodes_to_json_object(raw: str) -> bool:
try:
return isinstance(json.loads(raw), dict)
except (TypeError, ValueError):
return False Try / catch
try:
result = workflow.run(requirement)
except WorkflowExecutionError as e:
if "必须是 JSON 对象" in str(e):
# tool returned a list/scalar — wrap it: {"ok": true, "data": <that value>}
wrap_tool_result_as_object()
result = workflow.run(requirement)
else:
raise Prevention
- Always wrap list results: {"ok": true, "results": [...]} not a bare array.
- Watch for double json.dumps — it produces a string, not an object, after one parse.
- Include the object-shape requirement in the tool authoring guide/contributing docs.
When it happens
Trigger: A tool returns json.dumps([1,2,3]) (a list) or json.dumps(None); a tool stringifies a scalar like json.dumps('ok'); double-encoding like json.dumps(json.dumps(obj)) yields a string that parses to a string, not an object.
Common situations: Tools whose natural output is a list (search results, findings) and the author encoded the bare list; double-serialization bugs after refactoring; returning the result of another json.dumps call directly.
Related errors
- {stage}失败:工具返回的不是有效 JSON
- TMDB 返回非 JSON
- {stage}失败:工具执行异常:{exc}
- {stage}失败:{payload.get('message', '未知工具错误')}
- 无法选择 INBOX (状态: {select_status!r})
AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14).
Data as JSON: /api/errors/c07671619f09f8a9.
Report an issue: GitHub.