fix(repair): coerce empty metadata sentinel in both rebuild paths (+ docs catch-up) - #28
Merged
Merged
Conversation
Two functions construct the metadatas[] list that gets fed to
chromadb's upsert/add, both vulnerable to the same ValueError:
ValueError: Expected metadata to be a non-empty dict, got 0
metadata attributes in add.
chromadb 1.5.x's validate_metadata rejects both `None` and `{}`
entries — see chromadb/api/types.py:validate_metadata (line ~1071).
This commit patches both:
1. `_extract_drawers` (line ~131) — the chromadb-collection-based
extractor, used when the source palace's collection is openable
via the chromadb client. Sanitizes None/{} entries in the
`batch["metadatas"]` list to `{"_repaired_empty_meta": True}`
before extending `all_metas`.
2. `_rebuild_one_collection` (line ~813) — the SQLite-direct
extract path used by `rebuild_from_sqlite()`, invoked when the
source palace can't be opened via chromadb (the recovery path
for palaces with corrupt HNSW segments). Old code was:
metas.append(meta if meta else {})
The trailing `{}` was the bug; chromadb 1.5.x rejects empty
dicts the same as None. Replaced with the same sentinel.
Why `_repaired_empty_meta: True` as the sentinel:
- Satisfies chromadb's non-empty-dict requirement
- Bool-valued (valid chromadb metadata type, trivially serializable)
- Namespaced + descriptive so an operator can find which drawers
were coerced via `where={"_repaired_empty_meta": True}` later
- Idempotent on re-runs (a future repair over a sanitized palace
sees the sentinel as already-valid)
Verified on a 151,478-drawer production palace that previously
crashed at drawer 120,000 in both extract paths.
Fixes MemPalace#1458
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two YAML entries added (newest first): - `repair-empty-meta-sentinel` (commit `949cb20`, cherry-pick of jp/parallel-agent's `848774c`): both-locations fix for the metadata-sanitization bug class. Carries `pr: 1459` for the upstream slice; the YAML body documents the fork-only portion (`_rebuild_one_collection`). - `hooks-routing-via-palace-daemon` (commit `42ded2e`, already on main since PR #27 earlier today): the Stop/PreCompact routing change to palace-daemon's hook client. No `pr:` — fork-only deployment config with absolute paths. FORK_CHANGELOG.md regenerated from the updated YAML. CLAUDE.md row 38 added for the hooks change (the repair entry is exempt from row inventory via `pr: 1459`). `scripts/check-docs.sh` passes 5/5. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 11, 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.
Summary
Two changes in one PR:
Repair fix cherry-pick (commit
949cb20) — cherry-picks the parallel-agent commit848774cfromfix/repair-empty-metadataonto fork main. Fixes the chromadb-1.5.xValueError: Expected metadata to be a non-empty dictat both_extract_drawers(~L139) and_rebuild_one_collection(~L816). Coerces None and empty-dict metadata to{"_repaired_empty_meta": True}— satisfies chromadb's validator AND is discoverable later viawhere=for operator audit. The_extract_drawersslice is in upstream PR #1459; the_rebuild_one_collectionslice is fork-only for now.Doc-maintenance catch-up (commit
cdee4dc) — Two YAML entries:repair-empty-meta-sentinel(carriespr: 1459) andhooks-routing-via-palace-daemon(for the42ded2ecommit from PR fix(hooks): route Stop/PreCompact through palace-daemon/clients/hook.py #27 earlier today). FORK_CHANGELOG regenerated. CLAUDE.md row 38 added for the hooks change (the repair entry is exempt via thepr:field).Test plan
test_repairtests pass (no regression from the both-locations coerce)scripts/check-docs.shpasses 5/5🤖 Generated with Claude Code