Skip to content

Commit bb8da31

Browse files
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 <[email protected]>
1 parent e78345f commit bb8da31

File tree

2 files changed

+85
-2
lines changed

2 files changed

+85
-2
lines changed

src/basic_memory/markdown/entity_parser.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,13 @@ async def parse_file_content(self, absolute_path, file_content):
129129
file_stats = absolute_path.stat()
130130
metadata = post.metadata
131131

132-
# Ensure required fields have defaults (issue #184)
133-
metadata["title"] = post.metadata.get("title", absolute_path.stem)
132+
# Ensure required fields have defaults (issue #184, #387)
133+
# Handle title - use default if missing, None/null, empty, or string "None"
134+
title = post.metadata.get("title")
135+
if not title or title == "None":
136+
metadata["title"] = absolute_path.stem
137+
else:
138+
metadata["title"] = title
134139
# Handle type - use default if missing OR explicitly set to None/null
135140
entity_type = post.metadata.get("type")
136141
metadata["type"] = entity_type if entity_type is not None else "note"

tests/markdown/test_entity_parser_error_handling.py

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,84 @@ async def test_parse_file_with_null_entity_type(tmp_path):
183183
assert result.frontmatter.title == "Test File"
184184

185185

186+
@pytest.mark.asyncio
187+
async def test_parse_file_with_null_title(tmp_path):
188+
"""Test that files with explicit null title get default from filename (issue #387)."""
189+
# Create a file with null title
190+
test_file = tmp_path / "null_title.md"
191+
content = dedent(
192+
"""
193+
---
194+
title: null
195+
type: note
196+
---
197+
# Content
198+
"""
199+
).strip()
200+
test_file.write_text(content)
201+
202+
# Parse the file
203+
parser = EntityParser(tmp_path)
204+
result = await parser.parse_file(test_file)
205+
206+
# Should have default title from filename even when explicitly set to null
207+
assert result is not None
208+
assert result.frontmatter.title == "null_title" # Default from filename
209+
assert result.frontmatter.type == "note"
210+
211+
212+
@pytest.mark.asyncio
213+
async def test_parse_file_with_empty_title(tmp_path):
214+
"""Test that files with empty title get default from filename (issue #387)."""
215+
# Create a file with empty title
216+
test_file = tmp_path / "empty_title.md"
217+
content = dedent(
218+
"""
219+
---
220+
title:
221+
type: note
222+
---
223+
# Content
224+
"""
225+
).strip()
226+
test_file.write_text(content)
227+
228+
# Parse the file
229+
parser = EntityParser(tmp_path)
230+
result = await parser.parse_file(test_file)
231+
232+
# Should have default title from filename when title is empty
233+
assert result is not None
234+
assert result.frontmatter.title == "empty_title" # Default from filename
235+
assert result.frontmatter.type == "note"
236+
237+
238+
@pytest.mark.asyncio
239+
async def test_parse_file_with_string_none_title(tmp_path):
240+
"""Test that files with string 'None' title get default from filename (issue #387)."""
241+
# Create a file with string "None" as title (common in templates)
242+
test_file = tmp_path / "template_file.md"
243+
content = dedent(
244+
"""
245+
---
246+
title: "None"
247+
type: note
248+
---
249+
# Content
250+
"""
251+
).strip()
252+
test_file.write_text(content)
253+
254+
# Parse the file
255+
parser = EntityParser(tmp_path)
256+
result = await parser.parse_file(test_file)
257+
258+
# Should have default title from filename when title is string "None"
259+
assert result is not None
260+
assert result.frontmatter.title == "template_file" # Default from filename
261+
assert result.frontmatter.type == "note"
262+
263+
186264
@pytest.mark.asyncio
187265
async def test_parse_valid_file_still_works(tmp_path):
188266
"""Test that valid files with proper frontmatter still parse correctly."""

0 commit comments

Comments
 (0)