datawhalechina/hello-agents · warning · HTTPException
配置必须是 JSON 对象
Error message
配置必须是 JSON 对象
What it means
Raised by PUT /config/CONFIG when the submitted content parses as valid JSON but is not an object at the top level (json.loads succeeded, isinstance(config_data, dict) failed). The stored config.json must be a mapping because the code indexes 'llm' into it, so arrays or scalars are rejected with HTTP 400 before the file is written.
Source
Thrown at Co-creation-projects/tino-chen-HelloClaw/src/api/config.py:98
raise HTTPException(status_code=404, detail=f"配置文件 {name} 不存在")
return {"name": name, "content": content}
@router.put("/{name}")
async def update_config(name: str, request: ConfigUpdateRequest, ws: WorkspaceManager = Depends(get_workspace)):
"""更新配置文件"""
# 特殊处理 CONFIG (config.json)
if name == "CONFIG":
ensure_config_json_exists()
# 严格校验 JSON 格式
try:
config_data = json.loads(request.content)
except json.JSONDecodeError as e:
raise HTTPException(status_code=400, detail=f"无效的 JSON 格式: {str(e)}")
# 校验必需字段
if not isinstance(config_data, dict):
raise HTTPException(status_code=400, detail="配置必须是 JSON 对象")
if "llm" not in config_data:
raise HTTPException(status_code=400, detail="缺少必需字段: llm")
llm_config = config_data.get("llm", {})
required_fields = ["model_id", "api_key", "base_url"]
missing_fields = [f for f in required_fields if f not in llm_config]
if missing_fields:
raise HTTPException(status_code=400, detail=f"llm 配置缺少必需字段: {', '.join(missing_fields)}")
config_path = get_config_json_path()
with open(config_path, "w", encoding="utf-8") as f:
f.write(request.content)
return {"name": name, "status": "updated"}
# 处理 .md 配置文件
if name not in ws.list_configs():
raise HTTPException(status_code=404, detail=f"配置文件 {name} 不存在")View on GitHub (pinned to 606a07d341)
Solutions
- Wrap the payload in curly braces so the top-level value is an object: {"llm": {...}}
- Check the first non-whitespace character of the content is '{' before submitting
- Diff against the existing config.json (GET /config/CONFIG) to confirm the expected shape
Example fix
// before
content = JSON.stringify(["llm", {model_id: "gpt-4", api_key: "sk-...", base_url: "https://api.openai.com/v1"}])
// after
content = JSON.stringify({llm: {model_id: "gpt-4", api_key: "sk-...", base_url: "https://api.openai.com/v1"}}) Defensive patterns
Strategy: validation
Validate before calling
const parsed = JSON.parse(textareaValue);
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed)) {
showError('Top-level value must be a JSON object');
} Type guard
const isJsonObject = (v: unknown): v is Record<string, unknown> => typeof v === 'object' && v !== null && !Array.isArray(v);
Prevention
- Seed the editor with the existing config.json object, not a blank canvas
- Reject arrays/scalars client-side with a clear message before PUT
When it happens
Trigger: PUT /api/config/CONFIG with content like '["llm", {...}]', '"just a string"', '123', 'true', or 'null'. All parse cleanly but are not dicts.
Common situations: User wraps the config in an array thinking it is a list format; user saves a bare API-key string instead of the full object; frontend serializes the wrong variable (a value instead of the containing object).
Related errors
AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14).
Data as JSON: /api/errors/08ade99ff96ce9e6.
Report an issue: GitHub.