{"record":{"id":"13e8e6a611f5c0c9","repo":"datawhalechina/hello-agents","slug":"llm-13e8e6","errorCode":null,"errorMessage":"缺少必需字段: llm","messagePattern":"缺少必需字段: llm","errorType":"http","errorClass":"HTTPException","httpStatus":400,"severity":"warning","filePath":"Co-creation-projects/tino-chen-HelloClaw/src/api/config.py","lineNumber":101,"sourceCode":"\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\"}\n\n    # 处理 .md 配置文件\n    if name not in ws.list_configs():\n        raise HTTPException(status_code=404, detail=f\"配置文件 {name} 不存在\")\n\n    ws.save_config(name, request.content)\n    return {\"name\": name, \"status\": \"updated\"}","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/tino-chen-HelloClaw/src/api/config.py#L83-L119","documentation":"Raised by PUT /config/CONFIG when the parsed object has no 'llm' key. config.json is required to carry an 'llm' section because the agent reads model settings from it; a structurally valid object without that key is rejected with HTTP 400 before the write, so the on-disk file is never left half-configured.","triggerScenarios":"PUT /api/config/CONFIG with content like {\"model\": {...}} (key named differently), {\"LLM\": {...}} (wrong case), or {} (empty object).","commonSituations":"Renaming the key to match a newer config schema; user trimmed the file down to unrelated settings; frontend builds the object from optional form fields and omits llm entirely when its sub-form is untouched.","solutions":["Add an \"llm\" object as a top-level key: {\"llm\": {...}}","Check for exact lowercase spelling 'llm' — the check is case-sensitive","Start from GET /config/CONFIG output and edit values rather than building the file from scratch"],"exampleFix":"// before\ncontent = JSON.stringify({model: {model_id: \"gpt-4\"}})\n// after\ncontent = JSON.stringify({llm: {model_id: \"gpt-4\", api_key: \"sk-...\", base_url: \"https://api.openai.com/v1\"}})","handlingStrategy":"validation","validationCode":"const parsed = JSON.parse(content);\nif (!('llm' in parsed)) showError('Missing required top-level key: llm');","typeGuard":"const hasLlm = (v: Record<string, unknown>): v is Record<string, unknown> & { llm: unknown } =>\n  'llm' in v;","tryCatchPattern":null,"preventionTips":["Treat GET /config/CONFIG output as the schema template","Remember the key check is case-sensitive: exactly 'llm'"],"tags":["fastapi","json","config","validation","http-400"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}