zylon-ai/private-gpt · error · SkillDomainError
MISSING_FRONTMATTER
MISSING_FRONTMATTER
Error message
SKILL.md must start with YAML frontmatter
What it means
parse_skill_markdown expects the SKILL.md content to begin with a YAML frontmatter block (delimited --- fences) matched by _FRONTMATTER_RE; when the regex does not match at position 0 it raises SkillDomainError with code MISSING_FRONTMATTER. This means the parser found no opening fence/structure at the very start of the document — frontmatter must literally be the first thing in the file.
Source
Thrown at private_gpt/components/skills/parser.py:78
@field_validator("allowed_tools_raw", mode="before")
@classmethod
def normalize_list_or_str(cls, value: str | list[str] | None) -> str | None:
if value is None:
return None
if isinstance(value, list):
return " ".join(str(item).strip() for item in value if str(item).strip())
return value
class ParsedSkillDocument(BaseModel):
frontmatter: SkillFrontmatter
body: str = Field(default="")
def parse_skill_markdown(skill_markdown: str) -> ParsedSkillDocument:
match = _FRONTMATTER_RE.match(skill_markdown)
if not match:
raise SkillDomainError(
SkillErrorCode.MISSING_FRONTMATTER,
"SKILL.md must start with YAML frontmatter",
)
raw_frontmatter = match.group(1)
try:
parsed_yaml = yaml.safe_load(raw_frontmatter)
except yaml.YAMLError as e:
raise SkillDomainError(
SkillErrorCode.INVALID_FRONTMATTER,
"The SKILL.md frontmatter is not valid YAML.",
) from e
if not isinstance(parsed_yaml, dict):
raise SkillDomainError(
SkillErrorCode.INVALID_FRONTMATTER,
"Invalid SKILL.md frontmatter",
)
View on GitHub (pinned to 4a030776a3)
Solutions
- Make '---' the absolute first line, followed by YAML, closed by a second '---', then the body.
- Strip any leading whitespace/blank lines or BOM before parsing (`content.lstrip('\ufeff').lstrip()`).
- Ensure you pass the SKILL.md content, not another markdown file.
- Add an authoring-time lint that checks the file starts with '---'.
Example fix
# before # My Skill --- name: my-skill --- Body... # after --- name: my-skill --- # My Skill Body...
Defensive patterns
Strategy: validation
Validate before calling
def has_frontmatter(content: str) -> bool:
return bool(_FRONTMATTER_RE.match(content)) or content.startswith("---\n")
def normalize(content: str) -> str:
return content.lstrip("\ufeff").lstrip() Try / catch
try:
parsed = parse_skill_markdown(content)
except SkillDomainError as e:
if e.code is SkillErrorCode.MISSING_FRONTMATTER:
raise ValueError("SKILL.md must begin with a '---' YAML block; got bare markdown") from e
raise Prevention
- Make '---' the literal first line of every authored SKILL.md.
- Strip BOM and leading blank lines before parsing.
- Use a skill template/scaffold tool so structure is never hand-mistaken.
When it happens
Trigger: Calling parse_skill_markdown on a string that does not start with '---\n' frontmatter — e.g. a README-style markdown file, a SKILL.md beginning with prose or a BOM, or a file whose fences use '···' or are indented.
Common situations: Authors writing a title/intro line before the frontmatter; UTF-8 BOM prepended by Windows editors; using alternate fence styles or leaving a blank first line; passing the wrong file's content into the parser.
Related errors
- INVALID_FRONTMATTER
- NAME_INVALID_FORMAT
- Unsupported content block type: {type(block)}
- Invalid message order: expected {expected_roles} after {prev
- First message in the block must be a USER message.
AI-assisted analysis of zylon-ai/private-gpt@4a030776a3 (2026-08-15).
Data as JSON: /api/errors/c81c75e3afa34156.
Report an issue: GitHub.