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
- Start the file with a --- fence, include name: and description: in the frontmatter, close with ---, then add at least one line of markdown body.
- Validate the YAML block with a linter (yamllint / an editor YAML mode) before upload.
- 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
- Validate the frontmatter structure client-side before uploading.
- Use the official/default SKILL.md template as a starting point.
- Run YAML linting on edited frontmatter.
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
- start and end query params are required
- str(exc)
- Either user_id or email query parameter is required.
- Search query must be at least 3 characters.
- Unsupported grant_type: {request.grant_type}. Must be 'autho
AI-assisted analysis of Significant-Gravitas/AutoGPT@9c8bb5550f (2026-08-14).
Data as JSON: /api/errors/994ab0218474c4ba.
Report an issue: GitHub.