Skip to content

Commit e982900

Browse files
phernandezclaude
andcommitted
fix(core): strip null bytes from markdown content before database insert
PostgreSQL rejects null bytes (0x00) in text columns, causing CharacterNotInRepertoireError when syncing files like Claude agent definitions that contain embedded nulls. SQLite silently accepts them, so this only surfaces in cloud environments. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> Signed-off-by: phernandez <paul@basicmachines.co>
1 parent b3403e9 commit e982900

File tree

2 files changed

+25
-0
lines changed

2 files changed

+25
-0
lines changed

src/basic_memory/markdown/entity_parser.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,10 @@ async def parse_markdown_content(
249249

250250
content = strip_bom(content)
251251

252+
# PostgreSQL rejects null bytes (0x00) in text columns.
253+
# Some markdown files (e.g. Claude agent definitions) contain embedded nulls.
254+
content = content.replace("\x00", "")
255+
252256
# Parse frontmatter with proper error handling for malformed YAML.
253257
# We use frontmatter.parse() instead of frontmatter.loads() because
254258
# loads() does Post(content, handler, **metadata), which crashes when

tests/markdown/test_parser_edge_cases.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,27 @@ async def test_malformed_frontmatter(tmp_path):
176176
assert entity.frontmatter.permalink is None
177177

178178

179+
@pytest.mark.asyncio
180+
async def test_null_bytes_stripped(tmp_path):
181+
"""Test that null bytes are stripped from content before parsing.
182+
183+
PostgreSQL rejects null bytes (0x00) in text columns. Some files
184+
(e.g. Claude agent definitions) can contain embedded nulls.
185+
"""
186+
content = "---\ntitle: Test\ntype: note\n---\n\nSome content\x00with nulls\x00inside\n"
187+
188+
parser = EntityParser(tmp_path)
189+
entity = await parser.parse_markdown_content(
190+
file_path=tmp_path / "nulls.md",
191+
content=content,
192+
)
193+
194+
assert "\x00" not in entity.content
195+
assert "Some content" in entity.content
196+
assert "with nulls" in entity.content
197+
assert "inside" in entity.content
198+
199+
179200
@pytest.mark.asyncio
180201
async def test_file_not_found():
181202
"""Test handling of non-existent files."""

0 commit comments

Comments
 (0)