fix(chroma): reset chromadb System cache in ChromaBackend._client() on inode/mtime reopen - #2032
Merged
2 commits merged intoAug 12, 2026
Conversation
…n inode/mtime reopen _client() reconstructs PersistentClient on an inode/mtime change but did not drop chromadb's process-global SharedSystemClient cache first, so the rebuilt client reused the stale path-keyed System (and its in-memory HNSW segment) and could persist an outdated index over on-disk changes -- the same class as MemPalace#2002, reached via _client() instead of _get_client. Add SharedSystemClient.clear_system_cache() to the external-change branch of _client(), mirroring mcp_server._force_chroma_cache_reset (MemPalace#2026) and repair._close_chroma_handles. Backend-level regression test asserts the reset fires on the change reopen, strictly before the reconstruct, and not on first open (chroma-core/chroma#2536, #5843). Fixes MemPalace#2028.
Two monkeypatch.setattr calls were wrapped across lines that fit within the line length; ruff format --check flagged them. Formatter-only, no behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Gg6g5efZ1rNbBTHqGz2Tjw
7 tasks
83d8cbd
pull Bot
pushed a commit
to nenyatech-mirror/mempalace
that referenced
this pull request
Aug 12, 2026
This was referenced Aug 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #2028.
What
ChromaBackend._client()reconstructschromadb.PersistentClient(path=...)when it detects an inode/mtime change onchroma.sqlite3, but it did not first drop chromadb's process-globalSharedSystemClientcache. chromadb caches itsSystem(and the live HNSW segment) keyed by path, so the reconstructed client reused the stale in-memory segment and could persist an outdated index over a peer/rebuild's on-disk changes, the same data-loss class as #2002, reached through_client()instead ofmcp_server._get_client.This adds a
SharedSystemClient.clear_system_cache()call to the existing external-change branch of_client()(the same branch that already discards the quarantine gate), mirroring the reset thatmcp_server._force_chroma_cache_reset(#2026) andrepair._close_chroma_handlesalready perform on their paths.Why it was latent, and why fix it anyway
No shipped caller is currently exposed: the MCP server resets via
_force_chroma_cache_reset(#2026),repair._post_rebuild_cleanupresets via_close_chroma_handles, the daemon holds no chroma backend, and CLI/migrate run in short-lived processes that start with an empty chromadb cache. Today the invariant is upheld by callers remembering to reset out-of-band. This moves the invariant into the backend so a future in-process open→rebuild→reopen through_client()cannot silently reintroduce #2002.Upstream corroboration
The mechanism is documented in chromadb's own tracker:
clear_system_cache()is the accepted workaround.SharedSystemClient._identifier_to_systemcachesSysteminstances keyed bypersist_directoryand never evicts them, so a reopen at the same path reuses the cached System (and its in-memory HNSW segment).Caveat, disclosed: chromadb annotates
clear_system_cache()as intended for testing. This PR does not introduce a new dependency on it, the shippedmcp_server._force_chroma_cache_reset(#2026) andrepair._close_chroma_handlesalready call it; this change brings_client()in line with those existing paths. If the project would rather gate this behind a different eviction primitive, happy to follow.Scope notes
clear_system_cache()is process-global; chromadb exposes no per-path eviction (see #5843). It fires only on the inode/mtime-change branch, never the steady-state hot path, so the redundant-rebuild cost is bounded to genuine external-change reopens. The existing MCP and repair paths already accept this same global-clear cost.getattrguard match the style of the existing reset helpers, so a chromadb version withoutclear_system_cachedegrades to a logged debug rather than an error.Test
tests/test_backends.py::test_chroma_backend_resets_system_cache_on_inode_changescripts an inode swap between two_client()calls and asserts the cache reset fires on the change reopen, strictly before thePersistentClientreconstruction, and not on first open. Modeled on the existingtest_chroma_backend_requarantines_after_inode_replacement.Relates to #2002, #2026. Distinct from the daemon/single-writer work in #1976.