datawhalechina/hello-agents · error · WorkflowExecutionError
需求必须是字符串
Error message
需求必须是字符串
What it means
Raised by RequirementClarifierWorkflow._validate_requirement (src/workflow.py:118) when the requirement argument is not a str instance. Since Python type hints are not enforced at runtime, passing bytes, a dict, or None into run() hits this explicit guard instead of failing later with a confusing prompt error.
Source
Thrown at Co-creation-projects/zenith191-RequirementClarifierAgent/src/workflow.py:118
architecture=architecture,
risk_review=risk_review,
report=report,
quality=quality,
)
@staticmethod
def save_report(result: WorkflowResult, output_path: str | Path) -> Path:
"""以 UTF-8 保存最终 Markdown 报告。"""
path = Path(output_path)
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(result.report.rstrip() + "\n", encoding="utf-8")
return path
@staticmethod
def _validate_requirement(requirement: str) -> str:
if not isinstance(requirement, str):
raise WorkflowExecutionError("需求必须是字符串")
requirement = requirement.strip()
if not requirement:
raise WorkflowExecutionError("需求不能为空")
if len(requirement) > MAX_REQUIREMENT_LENGTH:
raise WorkflowExecutionError(
f"需求文本不能超过 {MAX_REQUIREMENT_LENGTH} 个字符"
)
return requirement
@staticmethod
def _run_agent(stage: str, agent: AgentLike, prompt: str) -> str:
try:
response = agent.run(prompt)
except Exception as exc:
raise WorkflowExecutionError(f"{stage}阶段执行失败:{exc}") from exc
if not isinstance(response, str) or not response.strip():
raise WorkflowExecutionError(f"{stage}阶段返回了空结果")
return response.strip()View on GitHub (pinned to 606a07d341)
Solutions
- Convert to str before calling run(): decode bytes, extract the text field from the dict, or str()-serialize deliberately.
- Fix the caller to pass requirement['text'] (or equivalent) rather than the wrapper object.
- Add an assertion/log at the API boundary so non-string payloads are caught there with better context.
Example fix
# before result = workflow.run(req.json()) # dict! # after result = workflow.run(req.json()["requirement"])
Defensive patterns
Strategy: type-guard
Validate before calling
def is_plain_text(v) -> bool:
return isinstance(v, str) and v.strip() != ""
# at the API boundary
payload = req.json()
requirement = payload.get("requirement") if isinstance(payload, dict) else None
if not is_plain_text(requirement):
raise ValueError("'requirement' must be a non-empty string") Type guard
def is_requirement_text(value: object) -> bool:
"""Narrows to a usable requirement string."""
return isinstance(value, str) and bool(value.strip())
assert is_requirement_text(requirement), type(requirement) Try / catch
from src.workflow import WorkflowExecutionError
try:
result = workflow.run(requirement)
except WorkflowExecutionError as e:
if "必须是字符串" in str(e):
requirement = str(requirement) # deliberate coercion, then retry once
result = workflow.run(requirement)
else:
raise Prevention
- Validate and normalize input at the API/CLI boundary, not deep in the workflow.
- Decode bytes and unwrap JSON objects before passing text downstream.
- Type-hint the boundary (pydantic model with requirement: str) so FastAPI rejects wrong types for you.
When it happens
Trigger: Calling workflow.run(requirement) with a dict parsed from JSON (e.g. {'text': '...'}), bytes read from a file, None from a failed upstream extraction, or an int/float ID.
Common situations: Gluing the workflow behind an API that decodes JSON and passes the whole request object; reading a file in 'rb' mode and forgetting .decode(); a None default from an optional form field flowing through.
Related errors
AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14).
Data as JSON: /api/errors/caec051c79512ddb.
Report an issue: GitHub.