datawhalechina/hello-agents · warning · HTTPException
无效的 JSON 格式: {str(e)}
Error message
无效的 JSON 格式: {str(e)} What it means
Raised by PUT /config/{name} when name is 'CONFIG' and the request body's content field is not parseable by json.loads. The endpoint stores config.json verbatim, so it validates the raw string before writing; a JSONDecodeError from the Python stdlib json module becomes HTTP 400 with the decoder's message appended (e.g. 'Expecting value: line 1 column 1'). It is a client-input error, not a server fault.
Source
Thrown at Co-creation-projects/tino-chen-HelloClaw/src/api/config.py:94
# 处理 .md 配置文件
content = ws.load_config(name)
if content is None:
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"}View on GitHub (pinned to 606a07d341)
Solutions
- Validate with JSON.parse (JS) or json.loads (Python) in the client before issuing the PUT
- Paste the content into jq . or any JSON linter to find the exact line/column named in the error message
- Ensure content is sent as a single escaped string inside the JSON request body, not as a nested raw object
- Strip BOM (\ufeff) and normalize smart quotes before saving
Example fix
// before
await fetch('/api/config/CONFIG', {method:'PUT', body: JSON.stringify({name:'CONFIG', content: textareaValue})});
// after
try { JSON.parse(textareaValue); } catch (e) { alert('Invalid JSON: ' + e.message); return; }
await fetch('/api/config/CONFIG', {method:'PUT', body: JSON.stringify({name:'CONFIG', content: textareaValue})}); Defensive patterns
Strategy: validation
Validate before calling
import json
def valid_config_json(content: str) -> bool:
try:
json.loads(content)
return True
except json.JSONDecodeError:
return False Prevention
- Always JSON.parse in the editor UI before enabling the save button
- Show the parser error next to the textarea so the user fixes it pre-submit
- Never send content read from a file without decoding BOM first
When it happens
Trigger: PUT /api/config/CONFIG with a body like {"name":"CONFIG","content":"not json"} or content containing trailing commas, single quotes, unescaped newlines, or smart quotes copied from a word processor. Also happens when the client sends the file already double-serialized ("{\"llm\":...}") or empty content.
Common situations: Frontend editing config.json in a plain textarea and saving without client-side JSON.parse validation; Chinese full-width quotes/colons pasted from docs; BOM at the start of the string; content truncated by a proxy or request-size limit.
Related errors
AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14).
Data as JSON: /api/errors/06c3473f6b57b529.
Report an issue: GitHub.