crewAIInc/crewAI · error · SystemExit

SKILL.md frontmatter must include a 'version' field before p

Error message

SKILL.md frontmatter must include a 'version' field before publishing.

What it means

Publishing requires a version string, read as `metadata.version` from the SKILL.md frontmatter (`raw_metadata.get("version")` when `metadata` is a dict). If absent, empty, or `metadata` itself is missing/not a mapping, the CLI exits because the registry needs an explicit version for each upload.

Source

Thrown at lib/cli/src/crewai_cli/skills/main.py:254

        name = frontmatter.get("name")
        raw_metadata = frontmatter.get("metadata")
        version = (
            raw_metadata.get("version") if isinstance(raw_metadata, dict) else None
        )
        description = frontmatter.get("description")

        if not name:
            console.print(
                "[red]SKILL.md frontmatter must include a 'name' field.[/red]"
            )
            raise SystemExit(1)

        if not version:
            console.print(
                "[red]SKILL.md frontmatter must include a 'version' field before publishing.[/red]"
            )
            raise SystemExit(1)

        settings = Settings()
        effective_org = org or settings.org_name
        if not effective_org:
            console.print(
                "[red]No organisation set. Run `crewai org switch <org_id>` first, "
                "or pass --org.[/red]"
            )
            raise SystemExit(1)

        self._print_current_organization()
        console.print(
            f"[bold blue]Publishing skill [bold]{name}[/bold] v{version} to {effective_org}...[/bold blue]"
        )

        archive_bytes = self._build_skill_tarball()
        encoded_file = "data:application/x-gzip;base64," + base64.b64encode(
            archive_bytes

View on GitHub (pinned to 754d7323be)

Solutions

  1. Add `metadata:\n version: "1.0.0"` to the frontmatter (quoted string recommended) and retry.
  2. Bump this version on every subsequent publish so the registry accepts the new upload.
  3. Ensure `metadata` is a YAML mapping, not a scalar string.

Example fix

# before
---
name: research-helper
version: "1.0.0"
---

# after
---
name: research-helper
metadata:
  version: "1.0.0"
---
Defensive patterns

Strategy: validation

Validate before calling

def has_version_field(path: str = "SKILL.md") -> bool:
    m = re.match(r"^---\n(.*?)\n---", Path(path).read_text(encoding="utf-8"), re.DOTALL)
    if not m:
        return False
    fm = yaml.safe_load(m.group(1)) or {}
    return isinstance(fm.get("metadata"), dict) and bool(fm["metadata"].get("version"))

Type guard

def has_publishable_version(fm: dict) -> bool:
    """True when metadata.version exists and is a non-empty scalar."""
    md = fm.get("metadata")
    return isinstance(md, dict) and bool(str(md.get("version") or "").strip())

Prevention

When it happens

Trigger: Running `crewai skill publish` where frontmatter lacks a `metadata:` block, has `metadata:` without a `version:` key, sets `version: ""`, or has `version` as a top-level key instead of under `metadata`. A YAML `version: 1.0.0` unquoted float still passes this check but is later sent as a number.

Common situations: Scaffolding by hand and forgetting version; placing `version:` at top level; bumping version in the wrong place before republishing.

Related errors


AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15). Data as JSON: /api/errors/335c3c7fb7b6c3dc. Report an issue: GitHub.