Skip to content

[GH-1147] Fix null byte crash in semantic memory ingestion#1165

Merged
jealous merged 3 commits into
MemMachine:mainfrom
o-love:fix/1147-null-byte-crash
Mar 18, 2026
Merged

[GH-1147] Fix null byte crash in semantic memory ingestion#1165
jealous merged 3 commits into
MemMachine:mainfrom
o-love:fix/1147-null-byte-crash

Conversation

@o-love

@o-love o-love commented Mar 3, 2026

Copy link
Copy Markdown
Contributor

Purpose of the change

Prevent asyncpg.CharacterNotInRepertoireError crashes caused by null bytes (\x00) in LLM-generated strings inserted into PostgreSQL TEXT columns.

Description

Implements defense-in-depth sanitization at two layers:

  1. Pydantic model layer (early catch): field_validator on SemanticCommand and LLMReducedFeature strips null bytes as soon as LLM output is parsed, before it reaches any storage code.
  2. PostgreSQL storage layer (backstop): A shared sanitize_pg_text() utility is called in add_feature() and update_feature() to strip null bytes from tag, feature, and value fields before insertion — catching any path that bypasses models (e.g. REST API direct inserts).

The sanitize_pg_text utility logs a warning when it strips null bytes so data-quality issues are visible in monitoring.

Fixes/Closes

Fixes #1147

Type of change

  • Bug fix (non-breaking change which fixes an issue)

How Has This Been Tested?

  • Unit Test
  • Integration Test

Tests added:

  • TestSanitizePgText — 10 unit tests covering clean passthrough, null byte stripping (single, multiple, leading, trailing, all-null), warning logging, and no-log for clean strings.
  • TestSemanticCommandNullByteStripping — 4 tests verifying the Pydantic validator strips null bytes from feature, tag, and value fields on SemanticCommand.
  • TestLLMReducedFeatureNullByteStripping — 4 tests verifying the same for LLMReducedFeature.
  • test_add_feature_with_null_bytes_does_not_crash — Regression test confirming null bytes in feature values do not crash storage insertion.

Test Results: 1329 passed, 9 skipped, 0 failures. Ruff lint and format clean.

Checklist

  • My code follows the style guidelines of this project (See STYLE_GUIDE.md)
  • I have performed a self-review of my own code
  • I have commented my code
  • My changes generate no new warnings
  • I have added unit tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • I have checked my code and corrected any misspellings

Screenshots/Gifs

N/A

Further comments

  • Not in scope: Fixing the LLM itself (upstream model behavior), per-feature error recovery in ingestion (separate follow-up), and Neo4j storage sanitization (handles null bytes differently).
  • The sanitize_pg_text utility is intentionally kept separate from the Pydantic validators so it can serve as a backstop for all PostgreSQL insertion paths, not just model-validated ones.

@o-love o-love force-pushed the fix/1147-null-byte-crash branch from 974e192 to 1664e78 Compare March 3, 2026 21:07
Add sanitize_pg_text utility to strip null bytes from text before
writing to PostgreSQL. Apply sanitization in PG storage add_feature
and update_feature, and add validators to SemanticCommand and
LLMReducedFeature to strip null bytes at model boundary.

Includes regression tests for null byte handling.

(Rebased onto main via path translation — packaging refactor applied)
@o-love o-love force-pushed the fix/1147-null-byte-crash branch from 1664e78 to e5c0b5f Compare March 3, 2026 21:10

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR addresses PostgreSQL ingestion crashes caused by null bytes (\x00) in LLM-generated strings by stripping null bytes at both the Pydantic model boundary and the PostgreSQL storage boundary.

Changes:

  • Added sanitize_pg_text() utility and applied it to key text fields in the SQLAlchemy pgvector semantic storage writes.
  • Added Pydantic field_validators to strip null bytes from LLM-parsed semantic command/feature payloads early.
  • Added unit + regression tests covering sanitization behavior and the original crash scenario.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/server/src/memmachine_server/semantic_memory/storage/text_sanitizer.py Introduces a shared PostgreSQL text sanitization helper with warning logging.
packages/server/src/memmachine_server/semantic_memory/storage/sqlalchemy_pgvector_semantic.py Applies sanitization when inserting/updating semantic features in PostgreSQL.
packages/server/src/memmachine_server/semantic_memory/semantic_model.py Adds Pydantic validator to strip null bytes from SemanticCommand fields.
packages/server/src/memmachine_server/semantic_memory/semantic_llm.py Adds Pydantic validator to strip null bytes from LLMReducedFeature fields.
packages/server/server_tests/memmachine_server/semantic_memory/test_semantic_model.py Adds tests verifying Pydantic null-byte stripping for SemanticCommand and LLMReducedFeature.
packages/server/server_tests/memmachine_server/semantic_memory/storage/test_text_sanitizer.py Adds unit tests for sanitize_pg_text() including warning logging behavior.
packages/server/server_tests/memmachine_server/semantic_memory/storage/test_semantic_storage.py Adds regression test to ensure add_feature() with null bytes doesn’t crash.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@o-love o-love requested review from edwinyyyu and malatewang March 9, 2026 17:43

@malatewang malatewang left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Besides of the null byte, are there any other special character can cause error? When access the database, probably we should catch the exception, log it and handle it properly

@o-love

o-love commented Mar 17, 2026

Copy link
Copy Markdown
Contributor Author

Besides of the null byte, are there any other special character can cause error? When access the database, probably we should catch the exception, log it and handle it properly

Looking at google. The null byte is the only one that Postgres doesn't allow.

@sscargal sscargal added this to the v0.3.3 milestone Mar 18, 2026
@sscargal

Copy link
Copy Markdown
Contributor

@o-love, could you please resolve the merge conflict so we can proceed with the merge? Thanks.

Signed-off-by: Oscar Love <olabradalove@gmail.com>
@jealous jealous merged commit de9bacb into MemMachine:main Mar 18, 2026
44 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: semantic memory background task crashes while running amemgym benchmark, asyncpg.exceptions.CharacterNotInRepertoireError

5 participants