{"record":{"id":"54733a773bbbbd88","repo":"agentscope-ai/agentscope","slug":"invalid-skill-at-skill-path-r-missing-or-malfor","errorCode":null,"errorMessage":"Invalid skill at {skill_path!r}: missing or malformed SKILL.md (requires 'name' and 'description' fields).","messagePattern":"Invalid skill at (.+?): missing or malformed SKILL\\.md \\(requires 'name' and 'description' fields\\)\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"src/agentscope/workspace/_local_workspace.py","lineNumber":797,"sourceCode":"        Args:\n            skill_path (`str`):\n                Absolute or relative path to the skill directory to copy.\n            agent_id (`str | None`, optional):\n                The agent taking ownership. ``None`` installs into the\n                default partition.\n\n        Raises:\n            ValueError: If the skill at ``skill_path`` is invalid (missing or\n                malformed ``SKILL.md``).\n        \"\"\"\n        skill_path = _normalize_local_path(skill_path)\n        skills_dir = await self._equip_partition(agent_id)\n        async with self._skill_lock:\n            os.makedirs(skills_dir, exist_ok=True)\n\n            result = await self._validate_and_hash_skill(skill_path)\n            if result is None:\n                raise ValueError(\n                    f\"Invalid skill at {skill_path!r}: missing or malformed \"\n                    \"SKILL.md (requires 'name' and 'description' fields).\",\n                )\n\n            _, raw_name, skill_hash = result\n\n            skills_file = await self._load_skills_file(skills_dir)\n            existing: dict[str, _SkillEntry] = skills_file[\"skills\"]\n\n            existing_hashes: set[str] = {e[\"hash\"] for e in existing.values()}\n            if skill_hash in existing_hashes:\n                logger.info(\n                    \"Skill '%s' (hash: %s...) already exists, skipping\",\n                    raw_name,\n                    skill_hash[:8],\n                )\n                return\n","sourceCodeStart":779,"sourceCodeEnd":815,"githubUrl":"https://github.com/agentscope-ai/agentscope/blob/e90f1c7592896cc95f6e5ee506194f533378247d/src/agentscope/workspace/_local_workspace.py#L779-L815","documentation":"Raised by LocalWorkspace.add_skill when the skill directory's SKILL.md is missing or does not contain both 'name' and 'description' fields (parsed during _validate_and_hash_skill). The library requires every skill to be a directory with a well-formed SKILL.md before it can be copied into the agent's skills partition. This is a validation error on user-supplied skill content.","triggerScenarios":"Calling add_skill(path) or add_skill_archive(...) where path (or the archive's skill root) has no SKILL.md, or the SKILL.md front-matter/table lacks a 'name' or 'description' entry; also triggered by an archive whose extracted root is not the skill directory itself.","commonSituations":"Zipping a skill folder's parent instead of the folder, typos in SKILL.md keys (e.g. 'desc' instead of 'description'), empty SKILL.md, YAML front-matter indentation errors, or pointing add_skill at a README-only directory.","solutions":["Inspect skill_path: confirm SKILL.md exists at its root and starts with valid front-matter containing non-empty 'name' and 'description'.","If using add_skill_archive, re-pack the archive so its root (or a single top-level dir) contains SKILL.md directly.","Validate SKILL.md parses as expected (e.g. python -c \"import frontmatter; print(frontmatter.load('SKILL.md'))\") before passing it.","Fix any YAML syntax errors (tabs, missing colons, unquoted special characters) in SKILL.md."],"exampleFix":"# before\nawait ws.add_skill(\"./my-skill\")   # my-skill/SKILL.md missing 'description'\n\n# after\n# my-skill/SKILL.md\n---\nname: my-skill\ndescription: Formats reports\n---\nawait ws.add_skill(\"./my-skill\")","handlingStrategy":"validation","validationCode":"import pathlib, frontmatter\n\ndef skill_is_valid(skill_path: str) -> bool:\n    md = pathlib.Path(skill_path) / \"SKILL.md\"\n    if not md.is_file():\n        return False\n    try:\n        post = frontmatter.load(md)\n    except Exception:\n        return False\n    return bool(post.get(\"name\")) and bool(post.get(\"description\"))","typeGuard":null,"tryCatchPattern":"try:\n    await ws.add_skill(path)\nexcept ValueError as e:\n    if \"SKILL.md\" in str(e):\n        log.warning(\"skill %s skipped: %s\", path, e)\n    else:\n        raise","preventionTips":["Ship a skill template with valid SKILL.md front-matter.","Validate SKILL.md in CI with a frontmatter parser before packaging.","Pack archives from inside the skill directory so SKILL.md is at the root."],"tags":["agentscope","skill","validation","skill-md","workspace"],"backgroundTag":"skill-manifest-validation-failed","analyzedSha":"e90f1c7592896cc95f6e5ee506194f533378247d","analyzedAt":"2026-08-28T18:24:12.087Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}