fix: prevent spurious 'metadata: {}' in frontmatter output (#530)

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Paul Hernandez
2026-01-31 12:17:10 -06:00
committed by GitHub
parent 8f962fdd87
commit e3ced49d9d
2 changed files with 95 additions and 1 deletions
+3 -1
View File
@@ -241,7 +241,9 @@ class EntityParser:
f"Failed to parse YAML frontmatter in {file_path}: {e}. "
f"Treating file as plain markdown without frontmatter."
)
post = frontmatter.Post(content, metadata={})
# Use Post(content) not Post(content, metadata={})
# The latter creates {"metadata": {}} in the metadata dict (issue #528)
post = frontmatter.Post(content)
# Normalize frontmatter values
metadata = normalize_frontmatter_metadata(post.metadata)
@@ -291,3 +291,95 @@ async def test_parse_valid_file_still_works(tmp_path):
assert result.frontmatter.title == "Valid File"
assert result.frontmatter.type == "knowledge"
assert result.frontmatter.tags == ["test", "valid"]
@pytest.mark.asyncio
async def test_invalid_yaml_does_not_add_metadata_key(tmp_path):
"""Test that invalid YAML doesn't create spurious 'metadata' key in frontmatter (issue #528).
This tests a bug where `frontmatter.Post(content, metadata={})` was used incorrectly.
The `metadata={}` kwarg creates a KEY called "metadata" in the metadata dict,
rather than setting the metadata to an empty dict.
This caused files with invalid YAML to get `metadata: {}` in their frontmatter output,
which is incorrect and confusing.
"""
# Create a file with completely broken YAML that will trigger the fallback path
test_file = tmp_path / "broken_yaml.md"
content = dedent(
"""
---
title: Invalid YAML
this is: [not, valid, yaml
missing: closing bracket
---
# Content
This file has broken YAML frontmatter.
"""
).strip()
test_file.write_text(content)
# Parse the file
parser = EntityParser(tmp_path)
result = await parser.parse_file(test_file)
# The metadata dict should NOT contain a "metadata" key
# This was the bug: frontmatter.Post(content, metadata={}) creates {"metadata": {}}
assert "metadata" not in result.frontmatter.metadata, (
"Frontmatter metadata should not contain a 'metadata' key. "
"This indicates the bug where Post(content, metadata={}) was used incorrectly."
)
# Should still have the expected defaults
assert result.frontmatter.title == "broken_yaml"
assert result.frontmatter.type == "note"
@pytest.mark.asyncio
async def test_frontmatter_roundtrip_preserves_user_metadata(tmp_path):
"""Test that parsing and re-serializing frontmatter preserves user fields (issue #528).
Users reported that after cloud sync, their custom frontmatter fields like 'citekey'
were being lost and replaced with defaults. This test ensures user metadata is preserved.
"""
from basic_memory.file_utils import dump_frontmatter
import frontmatter
# Create a file with user's custom frontmatter (like the bug report)
test_file = tmp_path / "litnote.md"
content = dedent(
'''
---
title: "My Document Title"
type: litnote
tags:
- research
- methodology
citekey: authorTitleYear2024
---
# Content here...
'''
).strip()
test_file.write_text(content)
# Parse the file
parser = EntityParser(tmp_path)
result = await parser.parse_file(test_file)
# User's custom fields should be preserved
assert result.frontmatter.title == "My Document Title"
assert result.frontmatter.type == "litnote" # NOT overwritten to "note"
assert "citekey" in result.frontmatter.metadata
assert result.frontmatter.metadata["citekey"] == "authorTitleYear2024"
# Simulate what write_frontmatter does
post = frontmatter.Post(result.content, **result.frontmatter.metadata)
output = dump_frontmatter(post)
# The output should NOT have duplicate frontmatter or metadata: {} key
assert output.count("---") == 2, "Should have exactly one frontmatter block (two --- delimiters)"
assert "metadata:" not in output, "Should not have 'metadata:' key in output"
assert "citekey: authorTitleYear2024" in output, "User's citekey should be preserved"
assert "type: litnote" in output, "User's type should be preserved"