larksuite/cli · error
SKILL.md frontmatter is not closed
Error message
SKILL.md frontmatter is not closed
What it means
parseRequiredSkills scans the leading `---` delimited YAML frontmatter of SKILL.md and throws "SKILL.md frontmatter is not closed" when the opening `---` block never terminates. The library refuses to guess which lines are frontmatter, so an unterminated block makes the skill's dependency declaration unparsable.
Source
Thrown at internal/skillpolicy/dependencies.go:62
// A UTF-8 text file may begin with one BOM. Normalize it before checking
// the delimiter so BOM-prefixed dependency metadata cannot be skipped.
content := strings.TrimPrefix(string(skillMD), "\uFEFF")
lines := strings.Split(content, "\n")
if strings.TrimRight(lines[0], "\r") != "---" {
return nil, nil
}
block := make([]string, 0, len(lines))
closed := false
for _, line := range lines[1:] {
if strings.TrimRight(line, "\r") == "---" {
closed = true
break
}
block = append(block, line)
}
if !closed {
return nil, fmt.Errorf("SKILL.md frontmatter is not closed")
}
var frontmatter struct {
Metadata struct {
Requires struct {
Skills []string `yaml:"skills"`
} `yaml:"requires"`
} `yaml:"metadata"`
}
if err := yaml.Unmarshal([]byte(strings.Join(block, "\n")), &frontmatter); err != nil {
return nil, fmt.Errorf("cannot parse SKILL.md frontmatter: %w", err)
}
required := frontmatter.Metadata.Requires.Skills
seen := make(map[string]struct{}, len(required))
out := make([]string, 0, len(required))
for _, dependency := range required {
if !isSkillName(dependency) {View on GitHub (pinned to 7fd6ef3c07)
Solutions
- Add the closing `---` line immediately after the frontmatter keys, at column 0
- Remove any leading whitespace before both `---` delimiters
- Run the skill-format check (node scripts/skill-format-check/index.js) to catch malformed frontmatter
- Validate the SKILL.md against a known-good skill file's structure
Example fix
// before
---
metadata:
requires:
skills: [foo]
(no closing delimiter)
// after
---
metadata:
requires:
skills: [foo]
--- Defensive patterns
Strategy: validation
Validate before calling
func frontmatterClosed(data []byte) bool {
lines := strings.Split(string(data), "\n")
if len(lines) == 0 || strings.TrimSpace(lines[0]) != "---" { return false }
for _, l := range lines[1:] {
if strings.TrimSpace(l) == "---" { return true }
}
return false
}
// if !frontmatterClosed(skillMD) { fix the file } Try / catch
if _, err := parseRequiredSkills(name, data); err != nil {
if strings.Contains(err.Error(), "frontmatter is not closed") {
return fmt.Errorf("skill %s: add the closing '---' line after the frontmatter block", name)
}
return err
} Prevention
- Always close frontmatter with `---` at column 0
- Run node scripts/skill-format-check/index.js on skill files in CI
- Avoid hand-editing SKILL.md frontmatter without re-validating
- Lint for indented or malformed --- delimiters
When it happens
Trigger: SKILL.md starts with `---` but no matching closing `---` line appears before the scan ends — e.g. the closing delimiter was deleted, indented, or written as `----`/```---` with extra characters.
Common situations: Hand-editing SKILL.md and accidentally removing the second `---`; copy-pasting frontmatter that lost its trailing delimiter; a templating step truncating the file; writing the delimiter with leading whitespace so it is not recognized.
Related errors
- cannot parse SKILL.md frontmatter: %w
- required skill %q declared by %q is not a valid skill name
- host embedded skill content is invalid
- policy yaml %q: %w
- stat policy yaml %q: %w
AI-assisted analysis of larksuite/cli@7fd6ef3c07 (2026-09-04).
Data as JSON: /api/errors/7fe1b935140fae86.
Report an issue: GitHub.