fix(memory): don't crash search on FTS5 query syntax in user/LLM text - #43435
fix(memory): don't crash search on FTS5 query syntax in user/LLM text#43435ly-wang19 wants to merge 1 commit into
Conversation
|
Positive verification: FTS5 crash fix Reviewed this PR in detail — the fix is clean and well-structured:
The No issues found. This is a good defensive fix for a crash path exposed to arbitrary LLM/user input. |
|
Verification: FTS5 crash guard — looks clean. The Test coverage is thorough — parametrized across 9 metasyntax variants plus explicit regression tests for colon queries finding matches through the safe path, prefix queries still working (raw path succeeds first), and empty-after-sanitization returning |
austinpickett
left a comment
There was a problem hiding this comment.
✅ Approved
The bug: search_facts in holographic/store.py passed the raw LLM search query directly to FTS5 MATCH. LLM queries routinely contain FTS5 reserved syntax (bare AND/OR/NEAR, colons, unmatched quotes, parens), raising sqlite3.OperationalError and crashing the memory tool.
The fix: Retry path via _fts5_safe_query wraps each whitespace token in double quotes (escaping embedded double-quotes via doubling). The try/except → safe retry pattern is correct and the function is properly unit-tested. Gracefully returns [] when the sanitized query is empty.
Note: PR #43490 applies the same pattern to retrieval.py's _fts_candidates — different file, no conflict, both are wanted.
Reviewed by Hermes Agent
|
Small, self-contained fix for an unhandled It's one file + tests, still merges cleanly on current |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for the focused regression coverage. The direct-store crash is still present on current main, but the implementation needs a small adaptation to the newer query path.
Problems
- Current main now derives
match_querythroughFactRetriever._sanitize_fts_querybefore executingMATCH(plugins/memory/holographic/store.py:254-277, commit638d2e7bfcad1be6e779c0d1af95481a6e92d811). The original raw-query hunk therefore no longer applies directly. - The remaining defect is narrower but real: the sanitizer returns raw input when no tokens survive (
plugins/memory/holographic/retrieval.py:616-618), andsearch_factsexecutes it directly. Inputs such asAND,a OR, and quote-only text can therefore still raise from FTS5.
Suggested changes
- Preserve the current sanitizer and adapt the store-side fallback/guard around the direct
MATCHcall. - Retain the proposed direct-store regressions, particularly the all-token-discarded inputs above.
Automated hermes-sweeper review.
| safe = _fts5_safe_query(query) | ||
| if not safe: | ||
| return [] | ||
| params[0] = safe |
There was a problem hiding this comment.
Current main now builds match_query through FactRetriever._sanitize_fts_query before this execution path (638d2e7). Please preserve that sanitizer when salvaging this guard: its raw fallback for all-discarded tokens is the remaining crash path.
9d44df4 to
e4a2f11
Compare
MemoryStore.search_facts() passed the raw search string straight to FTS5 `MATCH`, so any text containing FTS5 metasyntax — a stray double-quote, a `key:value` colon, a bare `AND`/`OR`/`NEAR`, or a parenthesis — raised an unhandled sqlite3.OperationalError and crashed the memory tool. The memory `search` action is exposed to the LLM, which routinely emits such queries (e.g. `memory:safe`, `say "hi`, `foo AND bar`). Retry on OperationalError with each whitespace token quoted as a literal phrase (_fts5_safe_query), so the search degrades to a sane literal match instead of crashing. Valid FTS5 queries (including prefix `term*`) are unaffected — the raw query is tried first. Adds tests for the crashing-input set, the colon-query fallback still finding a match, normal/prefix queries unchanged, and the sanitizer helper.
e4a2f11 to
6017b13
Compare
|
Rebased on current That surfaced something worth flagging, so I've narrowed this PR's claim: So this is no longer "FTS5 metasyntax crashes the memory tool" broadly — it's the residual bare-operator case the sanitizer doesn't cover. I dropped the now-obsolete Still worth landing IMO since an LLM-emitted query of just |
What & why
MemoryStore.search_facts()passes the raw search string straight to FTS5:But FTS5 has its own query grammar, so any search text containing FTS5 metasyntax raises an unhandled
sqlite3.OperationalErrorand crashes the memory tool. The memorysearchaction is exposed to the LLM, which routinely produces such queries. Reproduced (onmain):Stray double-quotes,
key:valuecolons, bareAND/OR/NEAR, and parens all blow up.Fix
Try the raw query first (so valid FTS5 — including prefix
term*— is unchanged); onOperationalError, retry with each whitespace token quoted as a literal phrase via_fts5_safe_query(), which neutralizes the metasyntax:So
memory:safedegrades to the phrase"memory safe"and still finds the Rust fact, instead of crashing.How to test
scripts/run_tests.sh tests/plugins/memory/test_holographic_store_search_fts5.py # 14 passedCovers the crashing-input set (quote/colon/AND/OR/NEAR/paren — all return a list, never raise), the colon-query fallback still matching, normal and prefix (
rust*) queries unchanged, quotes-only →[], and the_fts5_safe_querysanitizer.Platforms
Pure SQLite plugin logic; verified via the CI-parity runner.