bytedance/deer-flow · error · HTTPException
Unknown model '{model}'. Use a model name defined under `mod
Error message
Unknown model '{model}'. Use a model name defined under `models:` in config.yaml. What it means
422 from `_validate_model_exists`: the request's `model` field is not a key under `models:` in config.yaml. The check mirrors the harness `update_agent` tool so callers get an actionable error at write time instead of silent fallback plus repeated runtime warnings. It is best-effort: if app config cannot be loaded (bare/test deployment), the check is skipped.
Source
Thrown at backend/app/gateway/routers/agents.py:135
Mirrors the ``update_agent`` harness tool: without this, an unknown model
silently falls back to the default at runtime and the user sees confusing
repeated warnings on every later turn instead of an actionable error here.
``None``/empty means "use the global default" and is always allowed.
Best-effort: if the app config cannot be loaded (e.g. no ``config.yaml`` on
disk in a bare/test deployment), skip the check rather than failing the
write — the runtime still falls back to the default for an unknown model.
"""
if not model:
return
try:
app_config = get_app_config()
except Exception:
logger.warning("Could not load app config to validate agent model %r; skipping model existence check.", model)
return
if app_config.get_model_config(model) is None:
raise HTTPException(status_code=422, detail=f"Unknown model '{model}'. Use a model name defined under `models:` in config.yaml.")
def _merge_model_settings_update(value: AgentModelSettings, existing: AgentModelSettings | None) -> dict:
"""Merge an explicit ``model_settings`` update with existing sub-fields.
The top-level ``model_settings`` key is optional in update requests:
omitted means "preserve the current block", while explicit ``null`` means
"clear the block". Inside the block, omitted sub-fields should behave the
same way. This lets API callers update only ``temperature`` without
accidentally clearing an existing ``max_tokens``.
"""
merged = existing.model_dump(exclude_none=True) if existing is not None else {}
for field in value.model_fields_set:
field_value = getattr(value, field)
if field_value is None:
merged.pop(field, None)
else:
merged[field] = field_valueView on GitHub (pinned to 1dd6ba1acb)
Solutions
- Open config.yaml, list the keys under `models:`, and use one of those exact names
- Add a `models:` entry for the desired model if it is legitimately available
- Pass `model: null`/omit the field to inherit the global default
- Expose the configured model list to the frontend so pickers only offer valid names
Example fix
# before
PUT /agents/my-agent { "model": "gpt-4o" } # not in models: -> 422
# after
PUT /agents/my-agent { "model": "deepseek-chat" } # exact key from config.yaml models: Defensive patterns
Strategy: validation
Validate before calling
const knownModels = new Set(await fetchConfiguredModels()); // keys of models: in config.yaml
if (body.model && !knownModels.has(body.model)) {
throw new Error(`model ${body.model} not in config.yaml models:`);
} Type guard
const isKnownModel = (m: string | null | undefined, known: Set<string>) => m == null || m === '' || known.has(m);
Try / catch
try { await api.updateAgent(name, body); }
catch (e) {
if (e.status === 422 && /Unknown model/.test(e.detail)) { body.model = null; return api.updateAgent(name, body); }
throw e;
} Prevention
- Drive model pickers from the server's configured model list, never a hardcoded array
- Omit the model field rather than sending a guessed default
- Validate against config.yaml before importing agent definitions from another environment
When it happens
Trigger: Creating/updating an agent with `model: 'gpt-4o'` when config.yaml only defines e.g. `deepseek-chat` and `qwen-max`; passing a model id from a different environment; typos in model profile names.
Common situations: Copying agent configs between deployments with different `models:` blocks; model profiles renamed in config while stored agent definitions keep the old name; frontend model pickers not synced with server config.
Related errors
- Invalid agent name '{name}'. Must match ^[A-Za-z0-9-]+$ (let
- Failed to update MCP configuration
- channels.buzz.relay_url must be a ws:// or wss:// URL
- expected 64-hex or {bech_hrp}1... value
- expected exactly 32 bytes
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/6bb182f7373cfa02.
Report an issue: GitHub.