{"record":{"id":"69666401de63773d","repo":"OpenBMB/ChatDev","slug":"tooling-type-must-be-one-of-list-iter-tooling-typ","errorCode":null,"errorMessage":"tooling.type must be one of {list(iter_tooling_type_registrations().keys())}","messagePattern":"tooling\\.type must be one of (.+?)","errorType":"validation","errorClass":"ConfigError","httpStatus":null,"severity":"error","filePath":"entity/configs/node/tooling.py","lineNumber":630,"sourceCode":"            description=\"Configuration block validated by the chosen tool type (Python function list, MCP server settings, local command MCP launch, etc.).\",\n        ),\n    }\n\n    @classmethod\n    def child_routes(cls) -> Dict[ChildKey, type[BaseConfig]]:\n        return {\n            ChildKey(field=\"config\", value=name): config_cls\n            for name, config_cls in iter_tooling_type_registrations().items()\n        }\n\n    @classmethod\n    def from_dict(cls, data: Mapping[str, Any], *, path: str) -> \"ToolingConfig\":\n        mapping = require_mapping(data, path)\n        tooling_type = require_str(mapping, \"type\", path)\n        try:\n            config_cls = get_tooling_type_config(tooling_type)\n        except RegistryError as exc:\n            raise ConfigError(\n                f\"tooling.type must be one of {list(iter_tooling_type_registrations().keys())}\",\n                extend_path(path, \"type\"),\n            ) from exc\n\n        config_payload = mapping.get(\"config\")\n        if config_payload is None:\n            raise ConfigError(\"tooling requires config block\", extend_path(path, \"config\"))\n\n        config_obj = config_cls.from_dict(config_payload, path=extend_path(path, \"config\"))\n\n        prefix = optional_str(mapping, \"prefix\", path)\n        return cls(type=tooling_type, config=config_obj, prefix=prefix, path=path)\n\n    @classmethod\n    def field_specs(cls) -> Dict[str, ConfigFieldSpec]:\n        specs = super().field_specs()\n        type_spec = specs.get(\"type\")\n        if type_spec:","sourceCodeStart":612,"sourceCodeEnd":648,"githubUrl":"https://github.com/OpenBMB/ChatDev/blob/4fb2db0ea90375ce1059f44fe03ffbd191a7a169/entity/configs/node/tooling.py#L612-L648","documentation":"ToolingConfig.from_dict dispatches on tooling.type via a registry; when the type string has no registered config class (RegistryError), it re-raises as ConfigError listing all valid types (e.g. http, stdio-style entries).","triggerScenarios":"tooling.type: \"http2\", a typo like \"htp\", or a plugin type whose registration never ran (registry entry not imported).","commonSituations":"Upgrading versions that renamed/removed tooling types; custom tooling classes defined but never registered via the registration API; typos in hand-edited configs.","solutions":["Check the error message: it enumerates valid types — switch to one of them","Fix typos in tooling.type","For custom tooling, ensure the module registering the type is imported before from_dict runs"],"exampleFix":"# before\n{\"type\": \"stdioo\", \"config\": {...}}\n# after\n{\"type\": \"stdio\", \"config\": {...}}","handlingStrategy":"validation","validationCode":"from wherever import iter_tooling_type_registrations\nvalid = set(iter_tooling_type_registrations().keys())\nassert data[\"tooling\"][\"type\"] in valid","typeGuard":"def is_known_tooling_type(t: str) -> bool:\n    return t in iter_tooling_type_registrations()","tryCatchPattern":"except ConfigError as e:\n    if \"must be one of\" in str(e):\n        show_valid_types(e)  # message lists them; prompt user to pick","preventionTips":["Import plugin modules that register custom tooling types before loading configs","Re-check valid type names after library upgrades"],"tags":["config","registry","dispatch","tooling"],"backgroundTag":"unknown-config-type","analyzedSha":"4fb2db0ea90375ce1059f44fe03ffbd191a7a169","analyzedAt":"2026-08-27T14:35:29.622Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}