{"record":{"id":"06c3473f6b57b529","repo":"datawhalechina/hello-agents","slug":"json-str-e","errorCode":null,"errorMessage":"无效的 JSON 格式: {str(e)}","messagePattern":"无效的 JSON 格式: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"Co-creation-projects/tino-chen-HelloClaw/src/api/config.py","lineNumber":94,"sourceCode":"\n    # 处理 .md 配置文件\n    content = ws.load_config(name)\n    if content is None:\n        raise HTTPException(status_code=404, detail=f\"配置文件 {name} 不存在\")\n    return {\"name\": name, \"content\": content}\n\n\n@router.put(\"/{name}\")\nasync def update_config(name: str, request: ConfigUpdateRequest, ws: WorkspaceManager = Depends(get_workspace)):\n    \"\"\"更新配置文件\"\"\"\n    # 特殊处理 CONFIG (config.json)\n    if name == \"CONFIG\":\n        ensure_config_json_exists()\n        # 严格校验 JSON 格式\n        try:\n            config_data = json.loads(request.content)\n        except json.JSONDecodeError as e:\n            raise HTTPException(status_code=400, detail=f\"无效的 JSON 格式: {str(e)}\")\n\n        # 校验必需字段\n        if not isinstance(config_data, dict):\n            raise HTTPException(status_code=400, detail=\"配置必须是 JSON 对象\")\n\n        if \"llm\" not in config_data:\n            raise HTTPException(status_code=400, detail=\"缺少必需字段: llm\")\n\n        llm_config = config_data.get(\"llm\", {})\n        required_fields = [\"model_id\", \"api_key\", \"base_url\"]\n        missing_fields = [f for f in required_fields if f not in llm_config]\n        if missing_fields:\n            raise HTTPException(status_code=400, detail=f\"llm 配置缺少必需字段: {', '.join(missing_fields)}\")\n\n        config_path = get_config_json_path()\n        with open(config_path, \"w\", encoding=\"utf-8\") as f:\n            f.write(request.content)\n        return {\"name\": name, \"status\": \"updated\"}","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/tino-chen-HelloClaw/src/api/config.py#L76-L112","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nawait fetch('/api/config/CONFIG', {method:'PUT', body: JSON.stringify({name:'CONFIG', content: textareaValue})});\n// after\ntry { JSON.parse(textareaValue); } catch (e) { alert('Invalid JSON: ' + e.message); return; }\nawait fetch('/api/config/CONFIG', {method:'PUT', body: JSON.stringify({name:'CONFIG', content: textareaValue})});","handlingStrategy":"validation","validationCode":"import json\ndef valid_config_json(content: str) -> bool:\n    try:\n        json.loads(content)\n        return True\n    except json.JSONDecodeError:\n        return False","typeGuard":null,"tryCatchPattern":null,"preventionTips":["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"],"tags":["fastapi","json","config","validation","http-400"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}