datawhalechina/hello-agents · error · WorkflowExecutionError
{stage}失败:工具返回的不是有效 JSON
Error message
{stage}失败:工具返回的不是有效 JSON What it means
Raised by _run_tool when json.loads(raw_result) fails with TypeError or ValueError — i.e. the tool's return value is not valid JSON text. The workflow parses a strict string protocol: every tool must return a JSON-encoded string (TypeError fires when raw_result is None/non-str, ValueError when the string is malformed JSON).
Source
Thrown at Co-creation-projects/zenith191-RequirementClarifierAgent/src/workflow.py:153
raise WorkflowExecutionError(f"{stage}阶段返回了空结果")
return response.strip()
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)View on GitHub (pinned to 606a07d341)
Solutions
- Make the tool return json.dumps(payload) — always a JSON-encoded string of an object.
- Validate the tool standalone: json.loads(MyTool().run({...})) should succeed before wiring it into the registry.
- Keep the payload shape {"ok": bool, ...} so downstream checks (ok / message) also pass.
Example fix
# before
def run(self, params):
return {"ok": True, "result": 42} # dict, not JSON string
# after
import json
def run(self, params):
return json.dumps({"ok": True, "result": 42}) Defensive patterns
Strategy: type-guard
Validate before calling
# contract test every tool must pass before registration
import json
def tool_returns_json_object(tool, sample_params) -> bool:
raw = tool.run(sample_params)
try:
payload = json.loads(raw)
except (TypeError, ValueError):
return False
return isinstance(payload, dict) and "ok" in payload
assert tool_returns_json_object(my_tool, sample_params) Type guard
import json
def is_json_object_string(raw: object) -> bool:
"""True when raw is a string decoding to a JSON object."""
if not isinstance(raw, str):
return False
try:
return isinstance(json.loads(raw), dict)
except ValueError:
return False Try / catch
try:
result = workflow.run(requirement)
except WorkflowExecutionError as e:
if "不是有效 JSON" in str(e):
fix_tool_return_type() # make the tool json.dumps() its result
result = workflow.run(requirement)
else:
raise Prevention
- Standardize a small base class/helper: tools always return json.dumps({...}) with ok/message keys.
- Add contract tests for tools: valid JSON string, dict shape, ok present.
- Never return Python repr output or free text from tools consumed by this workflow.
When it happens
Trigger: A tool returns a Python dict directly (json.loads(dict) → TypeError); a tool returns plain text like 'done' (ValueError); a tool returns JSON with single quotes or trailing commas (ValueError).
Common situations: Writing a custom tool that returns json.dumps(...) inconsistently — or forgets dumps entirely; tools that return pretty-printed or Python-repr output; upgrading a tool that previously returned free text.
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/8a9a2ebd4da51f78.
Report an issue: GitHub.