agentscope-ai/agentscope · error · ValueError

Invalid skill at {skill_path!r}: missing or malformed SKILL.

Error message

Invalid skill at {skill_path!r}: missing or malformed SKILL.md (requires 'name' and 'description' fields).

What it means

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.

Source

Thrown at src/agentscope/workspace/_local_workspace.py:797

        Args:
            skill_path (`str`):
                Absolute or relative path to the skill directory to copy.
            agent_id (`str | None`, optional):
                The agent taking ownership. ``None`` installs into the
                default partition.

        Raises:
            ValueError: If the skill at ``skill_path`` is invalid (missing or
                malformed ``SKILL.md``).
        """
        skill_path = _normalize_local_path(skill_path)
        skills_dir = await self._equip_partition(agent_id)
        async with self._skill_lock:
            os.makedirs(skills_dir, exist_ok=True)

            result = await self._validate_and_hash_skill(skill_path)
            if result is None:
                raise ValueError(
                    f"Invalid skill at {skill_path!r}: missing or malformed "
                    "SKILL.md (requires 'name' and 'description' fields).",
                )

            _, raw_name, skill_hash = result

            skills_file = await self._load_skills_file(skills_dir)
            existing: dict[str, _SkillEntry] = skills_file["skills"]

            existing_hashes: set[str] = {e["hash"] for e in existing.values()}
            if skill_hash in existing_hashes:
                logger.info(
                    "Skill '%s' (hash: %s...) already exists, skipping",
                    raw_name,
                    skill_hash[:8],
                )
                return

View on GitHub (pinned to e90f1c7592)

Solutions

  1. Inspect skill_path: confirm SKILL.md exists at its root and starts with valid front-matter containing non-empty 'name' and 'description'.
  2. If using add_skill_archive, re-pack the archive so its root (or a single top-level dir) contains SKILL.md directly.
  3. Validate SKILL.md parses as expected (e.g. python -c "import frontmatter; print(frontmatter.load('SKILL.md'))") before passing it.
  4. Fix any YAML syntax errors (tabs, missing colons, unquoted special characters) in SKILL.md.

Example fix

# before
await ws.add_skill("./my-skill")   # my-skill/SKILL.md missing 'description'

# after
# my-skill/SKILL.md
---
name: my-skill
description: Formats reports
---
await ws.add_skill("./my-skill")
Defensive patterns

Strategy: validation

Validate before calling

import pathlib, frontmatter

def skill_is_valid(skill_path: str) -> bool:
    md = pathlib.Path(skill_path) / "SKILL.md"
    if not md.is_file():
        return False
    try:
        post = frontmatter.load(md)
    except Exception:
        return False
    return bool(post.get("name")) and bool(post.get("description"))

Try / catch

try:
    await ws.add_skill(path)
except ValueError as e:
    if "SKILL.md" in str(e):
        log.warning("skill %s skipped: %s", path, e)
    else:
        raise

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Related errors


AI-assisted analysis of agentscope-ai/agentscope@e90f1c7592 (2026-08-28). Data as JSON: /api/errors/54733a773bbbbd88. Report an issue: GitHub.