OpenBMB/ChatDev · error · ConfigError

tooling must be a list

Error message

tooling must be a list

What it means

The 'tooling' key of an agent model config is present and non-null but is not a JSON/YAML list. Tooling entries are parsed as a list of ToolingConfig objects, so any other shape fails immediately.

Source

Thrown at entity/configs/node/agent.py:370

        role = optional_str(mapping, "role", path)
        api_key = optional_str(mapping, "api_key", path)
        params = optional_dict(mapping, "params", path) or {}
        raw_input_mode = optional_str(mapping, "input_mode", path)
        input_mode = AgentInputMode.MESSAGES
        if raw_input_mode:
            try:
                input_mode = AgentInputMode(raw_input_mode.strip().lower())
            except ValueError as exc:
                raise ConfigError(
                    "model.input_mode must be 'prompt' or 'messages'",
                    extend_path(path, "input_mode"),
                ) from exc

        tooling_cfg: List[ToolingConfig] = []
        if "tooling" in mapping and mapping["tooling"] is not None:
            raw_tooling = mapping["tooling"]
            if not isinstance(raw_tooling, list):
                 raise ConfigError("tooling must be a list", extend_path(path, "tooling"))
            for idx, item in enumerate(raw_tooling):
                tooling_cfg.append(
                    ToolingConfig.from_dict(item, path=extend_path(path, f"tooling[{idx}]"))
                )

        thinking_cfg = None
        if "thinking" in mapping and mapping["thinking"] is not None:
            thinking_cfg = ThinkingConfig.from_dict(mapping["thinking"], path=extend_path(path, "thinking"))

        memories_cfg: List[MemoryAttachmentConfig] = []
        if "memories" in mapping and mapping["memories"] is not None:
            raw_memories = mapping["memories"]
            if not isinstance(raw_memories, list):
                raise ConfigError("memories must be a list", extend_path(path, "memories"))
            for idx, item in enumerate(raw_memories):
                memories_cfg.append(
                    MemoryAttachmentConfig.from_dict(item, path=extend_path(path, f"memories[{idx}]"))
                )

View on GitHub (pinned to 4fb2db0ea9)

Solutions

  1. Wrap single tool configs in a list: "tooling": [{...}] not {"tooling": {...}}
  2. Verify YAML uses dash-prefixed list items under 'tooling'
  3. Omit 'tooling' or set it to null when no tools are needed

Example fix

// before
"tooling": {"type": "web_search"}
// after
"tooling": [{"type": "web_search"}]
Defensive patterns

Strategy: validation

Validate before calling

tooling = cfg.get('model', {}).get('tooling')
if tooling is not None and not isinstance(tooling, list):
    cfg['model']['tooling'] = [tooling]

Type guard

def has_list_tooling(cfg: dict) -> bool:
    t = cfg.get('model', {}).get('tooling')
    return t is None or isinstance(t, list)

Try / catch

try:
    ModelConfig.from_dict(data, path='agent')
except ConfigError as e:
    if 'tooling' in e.path and isinstance(data['model'].get('tooling'), dict):
        data['model']['tooling'] = [data['model']['tooling']]
        ModelConfig.from_dict(data, path='agent')
    else:
        raise

Prevention

When it happens

Trigger: Passing tooling as a single dict (one tool instead of a list), a string, or a number: "tooling": {"type": "web_search"} instead of [{...}]. A null/absent tooling key is fine.

Common situations: Wrapping a single tool config directly instead of in a list — the most common shape mistake; hand-editing YAML and dropping the '- ' list marker.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of OpenBMB/ChatDev@4fb2db0ea9 (2026-08-27). Data as JSON: /api/errors/a1fc656ac9c32ac5. Report an issue: GitHub.