OpenBMB/ChatDev · error · ConfigError
tooling requires config block
Error message
tooling requires config block
What it means
ToolingConfig.from_dict requires a nested 'config' block alongside 'type'; if mapping['config'] is absent (None), ConfigError is raised at path '...config'. The type-specific parser needs its payload there.
Source
Thrown at entity/configs/node/tooling.py:637
ChildKey(field="config", value=name): config_cls
for name, config_cls in iter_tooling_type_registrations().items()
}
@classmethod
def from_dict(cls, data: Mapping[str, Any], *, path: str) -> "ToolingConfig":
mapping = require_mapping(data, path)
tooling_type = require_str(mapping, "type", path)
try:
config_cls = get_tooling_type_config(tooling_type)
except RegistryError as exc:
raise ConfigError(
f"tooling.type must be one of {list(iter_tooling_type_registrations().keys())}",
extend_path(path, "type"),
) from exc
config_payload = mapping.get("config")
if config_payload is None:
raise ConfigError("tooling requires config block", extend_path(path, "config"))
config_obj = config_cls.from_dict(config_payload, path=extend_path(path, "config"))
prefix = optional_str(mapping, "prefix", path)
return cls(type=tooling_type, config=config_obj, prefix=prefix, path=path)
@classmethod
def field_specs(cls) -> Dict[str, ConfigFieldSpec]:
specs = super().field_specs()
type_spec = specs.get("type")
if type_spec:
registrations = iter_tooling_type_registrations()
metadata = iter_tooling_type_metadata()
type_names = list(registrations.keys())
default_value = type_names[0] if type_names else None
descriptions = {name: (metadata.get(name) or {}).get("summary") for name in type_names}
specs["type"] = replace(
type_spec,View on GitHub (pinned to 4fb2db0ea9)
Solutions
- Add a config block: {"type": "http", "config": {}} (empty dict is accepted)
- If defaults are all you need, pass config: {} rather than omitting it
- Keep tooling keys nested one level under config
Example fix
// before
{"tooling": {"type": "http"}}
// after
{"tooling": {"type": "http", "config": {}}} Defensive patterns
Strategy: validation
Validate before calling
tooling = data.get("tooling", {})
if "type" in tooling:
tooling.setdefault("config", {}) Type guard
def has_config_block(t: dict) -> bool:
return isinstance(t.get("config"), dict) Try / catch
except ConfigError as e:
if "requires config block" in str(e):
data["tooling"]["config"] = {}
retry_from_dict(data) Prevention
- Always pair type with config, even if empty {}
- Schema-validate required nested fields
When it happens
Trigger: {"tooling": {"type": "http"}} with no config key; config: null; config flattened one level up so its keys sit beside type.
Common situations: Hand-minimal configs omitting defaults; flattening the nesting by mistake when authoring JSON/YAML.
Related errors
- tooling must be a list
- cache_ttl must be numeric
- tool_sources must be a list of strings
- args entries must be strings
- env must be a mapping
AI-assisted analysis of OpenBMB/ChatDev@4fb2db0ea9 (2026-08-27).
Data as JSON: /api/errors/4a3f0e3c4536bb48.
Report an issue: GitHub.