caddyserver/caddy · error
unterminated front matter
Error message
unterminated front matter
What it means
Thrown by the templates module's front-matter parser (used by the split_frontmatter template function) when an opening fence (--- for YAML, + for TOML, { for JSON) is found but no matching closing fence appears before the end of input. The parser searches for '\n---', '\n+++', or '\n}' after the first line.
Source
Thrown at modules/caddyhttp/templates/frontmatter.go:64
if fmParser == nil {
// no recognized front matter; whole document is body
return nil, input, nil
}
// find end of front matter
var fmEndFence string
fmEndFenceStart := -1
for _, fence := range closingFence {
index := strings.Index(input[firstLineEnd:], "\n"+fence)
if index >= 0 {
fmEndFenceStart = index
fmEndFence = fence
break
}
}
if fmEndFenceStart < 0 {
return nil, "", fmt.Errorf("unterminated front matter")
}
fmEndFenceStart += firstLineEnd + 1 // add 1 to account for newline
// extract and parse front matter
frontMatter := input[firstLineEnd:fmEndFenceStart]
fm, err := fmParser([]byte(frontMatter))
if err != nil {
return nil, "", err
}
// the rest is the body
body := input[fmEndFenceStart+len(fmEndFence):]
return fm, body, nil
}
func yamlFrontMatter(input []byte) (map[string]any, error) {
m := make(map[string]any)View on GitHub (pinned to 50e54ee279)
Solutions
- Add the matching closing fence on its own line (--- for YAML, +++ for TOML, } for JSON)
- Ensure LF line endings and that the closing fence starts at column 0 with no leading spaces
- If the file has no front matter, do not pass it to split_frontmatter; branch with a contains/hasPrefix check first
- Test the document standalone with a YAML linter to confirm the front matter block is well formed
Example fix
<!-- before --> --- title: Broken No closing fence. <!-- after --> --- title: Fixed --- Body text.
Defensive patterns
Strategy: validation
Validate before calling
{{ $hasFM := strings.HasPrefix .Content "---" }}
{{ if $hasFM }}{{ $fm := splitFrontMatter .Content }}{{ end }}
# authoring-side check (Go):
# if bytes.HasPrefix(b, []byte("---")) && !bytes.Contains(b[len(b):], []byte("\n---")) { return errors.New("missing closing fence") } Prevention
- Lint markdown sources in CI to require balanced front-matter fences
- Use LF line endings for template sources
- Only call split_frontmatter on files known to have front matter
When it happens
Trigger: Calling {{ split_frontmatter .Content }} in a template where the document starts with '---' but never has a second '---' line; or a JSON front matter block whose closing '}' is not at the start of a line; or a TOML block missing the closing '+++'.
Common situations: Markdown files edited by hand where the closing fence was deleted, front matter authored with CRLF line endings so the '\n-' search behaves unexpectedly, files where the opening fence is the only line, or content that legitimately begins with '---' (e.g. an hr) but is fed through split_frontmatter anyway.
Related errors
- loading template extensions: %v
- delimiters must consist of exactly two elements: opening and
- root file system not specified
- parsing %s: %v
- virtual request cycle
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/5f75babeabb2a90f.
Report an issue: GitHub.