Skip to content

[Bug]: Markdown frontmatter at EOF loses metadata and title #7253

Closed as not planned

Description

@ktz03

Issue Origin

Observed or reproduced in a real environment

Bug Description

A Markdown document containing only YAML frontmatter loses its parsed metadata and frontmatter title when its closing --- is the last line without a final newline. Adding only that newline makes the same document work.

The existing parser contract says frontmatter is always parsed into metadata, and only removed from the stored body when explicitly requested. At the current head, the EOF case instead falls back to the filename title and retains the block even with extract_frontmatter=True.

Steps to Reproduce

  1. Use the current MarkdownParser layout path with ---\ntitle: Release Notes\nowner: team\n--- and source path notes.md.
  2. Inspect layout.doc_title, layout.meta, and planned write contents.
  3. Repeat with a final newline. Repeat for LF/CRLF and keep/remove modes.

Expected Behavior

Both versions parse {"title": "Release Notes", "owner": "team"} and use Release Notes as the title. Keep mode retains the exact input. Explicit removal leaves an empty body for this metadata-only document.

Actual Behavior

Without the final newline: title notes, metadata {}, and unchanged frontmatter text in both modes.
With the final newline: title Release Notes, frontmatter metadata present, exact input retained by default or an empty body with explicit removal.

Minimal Reproducible Example

import asyncio
from openviking.parse.parsers.markdown import MarkdownParser

async def main():
    document = "---\ntitle: Release Notes\nowner: team\n---"
    for content in (document, document + "\n"):
        layout = await MarkdownParser(extract_frontmatter=True)._compute_layout(
            content, "viking://temp/test", source_path="notes.md"
        )
        print(layout.doc_title, layout.meta)
        print([op.content for op in layout.ops if op.kind == "write"])

asyncio.run(main())

Error Logs

No exception; metadata/title differ solely because of the final newline.

OpenViking Version

Source head c0ed2dbbe8ddf0d0311655243b8ee8f3a72a352f.

Python Version

Python 3.12.14, PyYAML 6.0.3.

Operating System

Windows

Model Backend

Other — no model call involved.

Additional Context

The real complete parser/config classes and applicable constants were compiled from pinned source AST and the production _compute_layout coroutine was executed for eight ordinary input/control combinations. This avoids unavailable package initialization; it is not a full installed-package pytest, VFS apply, server-ingestion, or model run. The snippet above shows the corresponding normal import in a fully installed checkout.

The execution path is parse_content -> _compute_layout -> _extract_frontmatter. The owning regex currently requires a newline after the closing delimiter. The minimal proposal is to accept a complete closing-delimiter line followed by LF/CRLF or EOF, preserving keep/remove behavior and rejecting delimiter prefixes.

Related CRLF work in #6819 and #6737 retains the trailing-newline requirement; this report is limited to EOF. I can implement the focused fix and extend the existing frontmatter layout contract coverage.

Activity

  1. moved this from Backlog to In progress in OpenViking projecton Nov 9, 2026
  2. qin-ctx commented on Nov 10, 2026

    @qin-ctx
    Collaborator

    Thanks for reporting this. We confirmed that a frontmatter-only document without a final newline falls back to its filename and has no parsed frontmatter metadata. Default ingestion still preserves the complete source text.

    The practical impact is limited, and our priority is to use filenames as the basis for resource URIs. We do not plan to pursue this edge-case fix, so we are closing this issue as not planned along with #7255.

  3. moved this from In progress to Done in OpenViking projecton Nov 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions