datawhalechina/hello-agents · warning · HTTPException

缺少必需字段: llm

Error message

缺少必需字段: llm

What it means

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.

Source

Thrown at Co-creation-projects/tino-chen-HelloClaw/src/api/config.py:101

@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"}

    # 处理 .md 配置文件
    if name not in ws.list_configs():
        raise HTTPException(status_code=404, detail=f"配置文件 {name} 不存在")

    ws.save_config(name, request.content)
    return {"name": name, "status": "updated"}

View on GitHub (pinned to 606a07d341)

Solutions

  1. Add an "llm" object as a top-level key: {"llm": {...}}
  2. Check for exact lowercase spelling 'llm' — the check is case-sensitive
  3. Start from GET /config/CONFIG output and edit values rather than building the file from scratch

Example fix

// before
content = JSON.stringify({model: {model_id: "gpt-4"}})
// after
content = JSON.stringify({llm: {model_id: "gpt-4", api_key: "sk-...", base_url: "https://api.openai.com/v1"}})
Defensive patterns

Strategy: validation

Validate before calling

const parsed = JSON.parse(content);
if (!('llm' in parsed)) showError('Missing required top-level key: llm');

Type guard

const hasLlm = (v: Record<string, unknown>): v is Record<string, unknown> & { llm: unknown } =>
  'llm' in v;

Prevention

When it happens

Trigger: PUT /api/config/CONFIG with content like {"model": {...}} (key named differently), {"LLM": {...}} (wrong case), or {} (empty object).

Common situations: 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.

Related errors


AI-assisted analysis of datawhalechina/hello-agents@606a07d341 (2026-08-14). Data as JSON: /api/errors/13e8e6a611f5c0c9. Report an issue: GitHub.