bmad-code-org/BMAD-METHOD · error · ValueError
.memlog.md frontmatter is not terminated
Error message
.memlog.md frontmatter is not terminated
What it means
After confirming the opening `---`, `split` searches for the next line that is exactly `---`. If none exists before EOF, the frontmatter is unterminated and the body cannot be located, so it raises. The closing fence must be a full line of exactly three dashes; a fence with trailing characters or indentation is not recognised, which is deliberate so that `---` inside a free-text topic/goal value cannot truncate the header.
Source
Thrown at src/scripts/memlog.py:101
def resolve(args) -> Path:
"""The memlog file, from either addressing mode: {workspace}/.memlog.md or an explicit --path."""
return Path(args.path) if args.path else Path(args.workspace) / MEMLOG
def split(text: str) -> tuple[dict, str]:
"""Return (frontmatter dict in source order, body str). Frontmatter is plain key: value.
The closing fence is the first line that is *exactly* `---`, so a `---` inside a
field value (topic/goal are free user text) never truncates the frontmatter.
"""
lines = text.splitlines()
if not lines or lines[0] != "---":
raise ValueError(".memlog.md has no frontmatter")
end = next((i for i in range(1, len(lines)) if lines[i] == "---"), None)
if end is None:
raise ValueError(".memlog.md frontmatter is not terminated")
meta: dict[str, str] = {}
for line in lines[1:end]:
if ":" in line:
k, v = line.split(":", 1)
meta[k.strip()] = v.strip()
return meta, "\n".join(lines[end + 1:]).lstrip("\n")
def render(meta: dict, body: str) -> str:
# Neutralize newlines in values so a multi-line field can't break the fence on re-read.
fm = "\n".join(f"{k}: {' '.join(str(v).splitlines())}" for k, v in meta.items())
return "---\n" + fm + "\n---\n\n" + body.rstrip("\n") + "\n"
def touch(meta: dict) -> None:
"""Stamp `updated` and keep it last so the field order stays predictable."""
meta.pop("updated", None)
meta["updated"] = now()View on GitHub (pinned to b70486b9bd)
Solutions
- Add a line that is exactly `---` after the last frontmatter field.
- Strip trailing whitespace from the intended closing-fence line.
- If a frontmatter value legitimately contains `---`, that is fine — just ensure a real closing fence exists later; the parser takes the first exact match.
- Re-initialise with `memlog init` if the file is unrecoverable.
Example fix
# before (.memlog.md) --- topic: demo goal: show the fix - (note) hello # no closing fence # after --- topic: demo goal: show the fix updated: 2026-08-12T10:00 --- - (note) hello
Defensive patterns
Strategy: validation
Validate before calling
lines = text.splitlines() assert lines[0] == '---' assert any(ln == '---' for ln in lines[1:]), '.memlog.md frontmatter is not terminated'
Type guard
def frontmatter_is_terminated(text: str) -> bool:
lines = text.splitlines()
return bool(lines) and lines[0] == '---' and any(ln == '---' for ln in lines[1:]) Try / catch
from memlog import split
try:
meta, body = split(text)
except ValueError as e:
print(f"error: {e}", file=sys.stderr); sys.exit(2) Prevention
- Always close the frontmatter with a line of exactly three dashes.
- Avoid trailing whitespace on the closing fence.
- Use `memlog init` and `memlog append`/`set` so the file shape stays valid.
When it happens
Trigger: A file with an opening fence but no closing one (truncated write, partial paste); the closing line has trailing spaces, an indented fence, or four dashes; a frontmatter value contains a line that looks like a fence but the real closer was deleted.
Common situations: An interrupted write that left the file half-finished; an editor that 'helpfully' reformatted the fence; a manual edit that removed the closing line.
Related errors
- .memlog.md has no frontmatter
- --extra must be a JSON array of objects
- each --extra entry must be a JSON object, got: {item!r}
- --extra must be a JSON array of objects
- each --extra entry must be a JSON object, got: {item!r}
AI-assisted analysis of bmad-code-org/BMAD-METHOD@b70486b9bd (2026-08-13).
Data as JSON: /api/errors/1974407015efae43.
Report an issue: GitHub.