{"record":{"id":"0272049c17190244","repo":"OpenBMB/ChatDev","slug":"skill-name-is-required","errorCode":null,"errorMessage":"skill name is required","messagePattern":"skill name is required","errorType":"validation","errorClass":"ConfigError","httpStatus":null,"severity":"error","filePath":"entity/configs/node/skills.py","lineNumber":85,"sourceCode":"class AgentSkillSelectionConfig(BaseConfig):\n    name: str\n\n    FIELD_SPECS = {\n        \"name\": ConfigFieldSpec(\n            name=\"name\",\n            display_name=\"Skill Name\",\n            type_hint=\"str\",\n            required=True,\n            description=\"Discovered skill name from the default repo-level skills directory.\",\n        ),\n    }\n\n    @classmethod\n    def from_dict(cls, data: Mapping[str, Any], *, path: str) -> \"AgentSkillSelectionConfig\":\n        mapping = require_mapping(data, path)\n        name = mapping.get(\"name\")\n        if not isinstance(name, str) or not name.strip():\n            raise ConfigError(\"skill name is required\", extend_path(path, \"name\"))\n        return cls(name=name.strip(), path=path)\n\n    @classmethod\n    def field_specs(cls) -> Dict[str, ConfigFieldSpec]:\n        specs = super().field_specs()\n        name_spec = specs.get(\"name\")\n        if name_spec is None:\n            return specs\n\n        discovered = _discover_default_skills()\n        enum_values = [name for name, _ in discovered] or None\n        enum_options = [\n            EnumOption(value=name, label=name, description=description)\n            for name, description in discovered\n        ] or None\n        description = name_spec.description or \"Skill name\"\n        if not discovered:\n            description = (","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/OpenBMB/ChatDev/blob/4fb2db0ea90375ce1059f44fe03ffbd191a7a169/entity/configs/node/skills.py#L67-L103","documentation":"AgentSkillSelectionConfig.from_dict requires a non-empty 'name' string for each skill selection entry; missing, non-string, or whitespace-only names raise ConfigError('skill name is required') at '<path>.name'. It is called from _coerce_allow_entries when parsing allow-list entries.","triggerScenarios":"An allow-list skill entry mapping like {} or {name: '   '} or {name: 123} in the skills config.","commonSituations":"YAML entries with a typo'd key (nane:), entries that only have other keys like {path: ...}, or trimmed/empty names from templating.","solutions":["Ensure each mapping entry has a non-empty 'name' key","Use plain string entries for simple cases: allow: [my-skill]","Strip placeholder entries that have no name"],"exampleFix":"# before\nallow:\n  - description: helper\n# after\nallow:\n  - name: helper\n    description: helper","handlingStrategy":"validation","validationCode":"for entry in allow_list:\n    if isinstance(entry, dict):\n        assert isinstance(entry.get('name'), str) and entry['name'].strip()","typeGuard":"def is_valid_skill_entry(e) -> bool:\n    return (isinstance(e, str) and e.strip()) or (isinstance(e, dict) and isinstance(e.get('name'), str) and e['name'].strip())","tryCatchPattern":"try:\n    cfg = SkillsConfig.from_dict(d, path='skills')\nexcept ConfigError as e:\n    if 'skill name is required' in str(e):\n        d['allow'] = [e for e in d.get('allow', []) if isinstance(e, str) or (isinstance(e, dict) and e.get('name'))]\n        cfg = SkillsConfig.from_dict(d, path='skills')","preventionTips":["Prefer plain-string allow entries","Lint that each mapping entry has a non-empty 'name'"],"tags":["skills","config","missing-field"],"backgroundTag":"missing-required-config-field","analyzedSha":"4fb2db0ea90375ce1059f44fe03ffbd191a7a169","analyzedAt":"2026-08-27T14:35:29.622Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}