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

  1. Validate with JSON.parse (JS) or json.loads (Python) in the client before issuing the PUT
  2. Paste the content into jq . or any JSON linter to find the exact line/column named in the error message
  3. Ensure content is sent as a single escaped string inside the JSON request body, not as a nested raw object
  4. 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

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.