From bb8da314729f5769987108aec22f14ca10dfacb7 Mon Sep 17 00:00:00 2001 From: Paul Hernandez <60959+phernandez@users.noreply.github.com> Date: Tue, 21 Oct 2025 09:29:19 -0500 Subject: [PATCH] fix: Handle null, empty, and string 'None' title in markdown frontmatter (#387) (#389) Co-authored-by: claude[bot] <41898282+claude[bot]@users.noreply.github.com> Co-authored-by: Paul Hernandez --- src/basic_memory/markdown/entity_parser.py | 9 ++- .../test_entity_parser_error_handling.py | 78 +++++++++++++++++++ 2 files changed, 85 insertions(+), 2 deletions(-) diff --git a/src/basic_memory/markdown/entity_parser.py b/src/basic_memory/markdown/entity_parser.py index 8bc85afe..721a3153 100644 --- a/src/basic_memory/markdown/entity_parser.py +++ b/src/basic_memory/markdown/entity_parser.py @@ -129,8 +129,13 @@ class EntityParser: file_stats = absolute_path.stat() metadata = post.metadata - # Ensure required fields have defaults (issue #184) - metadata["title"] = post.metadata.get("title", absolute_path.stem) + # Ensure required fields have defaults (issue #184, #387) + # Handle title - use default if missing, None/null, empty, or string "None" + title = post.metadata.get("title") + if not title or title == "None": + metadata["title"] = absolute_path.stem + else: + metadata["title"] = title # Handle type - use default if missing OR explicitly set to None/null entity_type = post.metadata.get("type") metadata["type"] = entity_type if entity_type is not None else "note" diff --git a/tests/markdown/test_entity_parser_error_handling.py b/tests/markdown/test_entity_parser_error_handling.py index b607324f..787b6f32 100644 --- a/tests/markdown/test_entity_parser_error_handling.py +++ b/tests/markdown/test_entity_parser_error_handling.py @@ -183,6 +183,84 @@ async def test_parse_file_with_null_entity_type(tmp_path): assert result.frontmatter.title == "Test File" +@pytest.mark.asyncio +async def test_parse_file_with_null_title(tmp_path): + """Test that files with explicit null title get default from filename (issue #387).""" + # Create a file with null title + test_file = tmp_path / "null_title.md" + content = dedent( + """ + --- + title: null + type: note + --- + # Content + """ + ).strip() + test_file.write_text(content) + + # Parse the file + parser = EntityParser(tmp_path) + result = await parser.parse_file(test_file) + + # Should have default title from filename even when explicitly set to null + assert result is not None + assert result.frontmatter.title == "null_title" # Default from filename + assert result.frontmatter.type == "note" + + +@pytest.mark.asyncio +async def test_parse_file_with_empty_title(tmp_path): + """Test that files with empty title get default from filename (issue #387).""" + # Create a file with empty title + test_file = tmp_path / "empty_title.md" + content = dedent( + """ + --- + title: + type: note + --- + # Content + """ + ).strip() + test_file.write_text(content) + + # Parse the file + parser = EntityParser(tmp_path) + result = await parser.parse_file(test_file) + + # Should have default title from filename when title is empty + assert result is not None + assert result.frontmatter.title == "empty_title" # Default from filename + assert result.frontmatter.type == "note" + + +@pytest.mark.asyncio +async def test_parse_file_with_string_none_title(tmp_path): + """Test that files with string 'None' title get default from filename (issue #387).""" + # Create a file with string "None" as title (common in templates) + test_file = tmp_path / "template_file.md" + content = dedent( + """ + --- + title: "None" + type: note + --- + # Content + """ + ).strip() + test_file.write_text(content) + + # Parse the file + parser = EntityParser(tmp_path) + result = await parser.parse_file(test_file) + + # Should have default title from filename when title is string "None" + assert result is not None + assert result.frontmatter.title == "template_file" # Default from filename + assert result.frontmatter.type == "note" + + @pytest.mark.asyncio async def test_parse_valid_file_still_works(tmp_path): """Test that valid files with proper frontmatter still parse correctly."""