{"record":{"id":"cff33795f581bd8a","repo":"datawhalechina/hello-agents","slug":"name","errorCode":null,"errorMessage":"配置文件 {name} 不存在","messagePattern":"配置文件 (.+?) 不存在","errorType":"http","errorClass":"HTTPException","httpStatus":404,"severity":"warning","filePath":"Co-creation-projects/tino-chen-HelloClaw/src/api/config.py","lineNumber":80,"sourceCode":"    configs.insert(0, \"CONFIG\")\n    return {\"configs\": configs}\n\n\n@router.get(\"/{name}\")\nasync def get_config(name: str, ws: WorkspaceManager = Depends(get_workspace)):\n    \"\"\"获取指定配置文件内容\"\"\"\n    # 特殊处理 CONFIG (config.json)\n    if name == \"CONFIG\":\n        ensure_config_json_exists()\n        config_path = get_config_json_path()\n        with open(config_path, \"r\", encoding=\"utf-8\") as f:\n            content = f.read()\n        return {\"name\": name, \"content\": content}\n\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 对象\")","sourceCodeStart":62,"sourceCodeEnd":98,"githubUrl":"https://github.com/datawhalechina/hello-agents/blob/606a07d341a47be773fab7f4b71177f53f96b2c3/Co-creation-projects/tino-chen-HelloClaw/src/api/config.py#L62-L98","documentation":"The GET config endpoint in src/api/config.py special-cases CONFIG (config.json, auto-created on demand) but for every other name calls ws.load_config(name) and raises HTTPException(404, '配置文件 {name} 不存在') when it returns None. So the 404 means the workspace has no config file matching the requested name — either the name is not one the workspace knows (AGENTS, BOOTSTRAP, ...) or the corresponding .md file genuinely is not on disk.","triggerScenarios":"GET /api/config/foo where foo.md was never created; requesting a name with wrong case or extra suffix (/api/config/AGENTS.md instead of /api/config/AGENTS); workspace not initialized so no config files exist yet; file deleted by a user through the UI or filesystem.","commonSituations":"Frontend building the config list before onboarding finished; manual API calls guessing endpoint names; case-sensitivity differences between macOS dev and Linux prod; config removed via update/PUT flow leaving stale UI entries.","solutions":["Discover valid names first: call the list endpoint of the config router (or ws.list_configs()) and use an exact name from it.","Match the expected casing/suffix — the route takes the bare name (AGENTS), not the filename (AGENTS.md).","If the workspace is new, complete its initialization/onboarding so standard config files are created.","Treat 404 on this route in clients as 'not created yet' and offer a create action (PUT the config) instead of erroring out."],"exampleFix":"# before\nr = requests.get(f\"{base}/api/config/AGENTS.md\")  # 404\n# after\nnames = requests.get(f\"{base}/api/config\").json()  # list valid config names\nr = requests.get(f\"{base}/api/config/AGENTS\")  # exact bare name\nr.raise_for_status()","handlingStrategy":"validation","validationCode":"names = {c[\"name\"] for c in requests.get(f\"{base}/api/config\").json()}\nif name not in names:\n    raise LookupError(f\"config {name!r} not in workspace; available: {sorted(names)}\")\ncontent = requests.get(f\"{base}/api/config/{name}\").json()[\"content\"]","typeGuard":null,"tryCatchPattern":"resp = requests.get(f\"{base}/api/config/{name}\")\nif resp.status_code == 404:\n    # not created yet — create it via PUT instead of failing\n    resp = requests.put(f\"{base}/api/config/{name}\", json={\"content\": default_content})\nresp.raise_for_status()","preventionTips":["Drive config pickers from the list endpoint, never hardcoded names","Use bare names (AGENTS) matching the workspace convention, exact case","Treat 404 as 'not created yet' and offer create (PUT) in the UI"],"tags":["fastapi","http-404","configuration","rest-api","workspace"],"backgroundTag":null,"analyzedSha":"606a07d341a47be773fab7f4b71177f53f96b2c3","analyzedAt":"2026-08-14T22:57:27.446Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}