Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/basic_memory/markdown/entity_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,13 @@ async def parse_file_content(self, absolute_path, file_content):
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"
Expand Down
78 changes: 78 additions & 0 deletions tests/markdown/test_entity_parser_error_handling.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""
Expand Down
Loading