Significant-Gravitas/AutoGPT · error · HTTPException

File is not a valid SKILL.md — expected YAML frontmatter wit

Error message

File is not a valid SKILL.md — expected YAML frontmatter with 'name' and 'description' followed by a markdown body.

What it means

Skill-upload endpoint returns 400 when `parse_skill_markdown(body.content)` returns None: the uploaded SKILL.md text does not match the canonical format — YAML frontmatter containing 'name' and 'description' followed by a markdown body. This is a client-side content-validation failure, not a server fault.

Source

Thrown at autogpt_platform/backend/backend/api/features/v1.py:2675

        409: {"description": "Per-user skill limit reached"},
    },
    dependencies=[Security(requires_user)],
)
async def upload_copilot_skill(
    user_id: Annotated[str, Security(get_user_id)],
    body: UploadCopilotSkillRequest,
) -> CopilotSkillInfo:
    """Create a user-distilled skill from an uploaded ``SKILL.md`` file.

    Parses the canonical frontmatter + body, then reuses
    :func:`backend.copilot.tools.skills.store_user_skill` so an uploaded skill
    is validated, capped, and persisted exactly like one the copilot distils
    via ``store_skill``.  Malformed files return 400, the per-user cap returns
    409, and an existing slug is overwritten (upsert).
    """
    parsed = parse_skill_markdown(body.content)
    if parsed is None:
        raise HTTPException(
            status_code=400,
            detail=(
                "File is not a valid SKILL.md — expected YAML frontmatter with "
                "'name' and 'description' followed by a markdown body."
            ),
        )
    try:
        stored = await store_user_skill(
            user_id,
            name=parsed.name,
            description=parsed.description,
            body=parsed.body,
            triggers=list(parsed.triggers),
            version=parsed.version,
        )
    except SkillLimitError as exc:
        raise HTTPException(status_code=409, detail=str(exc))
    except (VirusDetectedError, VirusScanError) as exc:

View on GitHub (pinned to 9c8bb5550f)

Solutions

  1. Start the file with a --- fence, include name: and description: in the frontmatter, close with ---, then add at least one line of markdown body.
  2. Validate the YAML block with a linter (yamllint / an editor YAML mode) before upload.
  3. Use a known-good default skill file as the template and edit from there.

Example fix

# before (invalid — no frontmatter)
# My Skill
Does stuff.

# after
---
name: my-skill
description: Does stuff on demand.
---
# My Skill
Runs when the user asks for stuff.
Defensive patterns

Strategy: validation

Validate before calling

function validateSkillMarkdown(content: string): string | null {
  const m = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
  if (!m) return 'Missing --- frontmatter fences';
  try {
    const fm = parseYaml(m[1]);
    if (!fm.name || !fm.description) return "Frontmatter needs 'name' and 'description'";
  } catch { return 'Frontmatter is not valid YAML'; }
  if (!m[2].trim()) return 'Body is empty';
  return null;
}

Type guard

function looksLikeSkillMarkdown(content: string): boolean {
  return /^---\r?\n[\s\S]*?\r?\n---\r?\n[\s\S]+/.test(content);
}

Try / catch

try {
  await api.uploadSkill(content);
} catch (e) {
  if (e.status === 400 && /valid SKILL\.md/.test(e.detail)) { showFormatHelp(); return; }
  throw e;
}

Prevention

When it happens

Trigger: POST upload of a SKILL.md whose frontmatter delimiters (---) are missing/unbalanced, whose YAML is invalid, whose frontmatter lacks name or description, or which has no markdown body after the frontmatter.

Common situations: Hand-edited skill files with tabs or unquoted colons breaking YAML; converting arbitrary .md files to 'skills' without adding frontmatter; copy-paste that drops the closing --- fence; uploading the file's binary bytes instead of decoded text.

Related errors


AI-assisted analysis of Significant-Gravitas/AutoGPT@9c8bb5550f (2026-08-14). Data as JSON: /api/errors/994ab0218474c4ba. Report an issue: GitHub.