{"record":{"id":"958d6319f1c644a0","repo":"MemPalace/mempalace","slug":"sqlite-exact-collection-self-collection-name-r","errorCode":null,"errorMessage":"sqlite_exact collection {self._collection_name!r} cannot mix embedding dimensions {sorted(distinct)}","messagePattern":"sqlite_exact collection (.+?) cannot mix embedding dimensions (.+?)","errorType":"validation","errorClass":"DimensionMismatchError","httpStatus":null,"severity":"error","filePath":"mempalace/backends/sqlite_exact.py","lineNumber":339,"sourceCode":"        if row is None:\n            raise CollectionNotInitializedError(self._collection_name)\n        return int(row[0])\n\n    def _collection_dimension(self, cur, collection_id: int) -> Optional[int]:\n        row = cur.execute(\n            \"SELECT dimension FROM collections WHERE id = ?\",\n            (collection_id,),\n        ).fetchone()\n        if row is None or row[0] is None:\n            return None\n        return int(row[0])\n\n    def _ensure_collection_dimension(self, cur, collection_id: int, dims: list[int]) -> None:\n        distinct = {int(dim) for dim in dims}\n        if not distinct:\n            return\n        if len(distinct) > 1:\n            raise DimensionMismatchError(\n                f\"sqlite_exact collection {self._collection_name!r} cannot mix \"\n                f\"embedding dimensions {sorted(distinct)}\"\n            )\n        dim = distinct.pop()\n        stored = self._collection_dimension(cur, collection_id)\n        if stored is None:\n            cur.execute(\n                \"UPDATE collections SET dimension = ? WHERE id = ?\",\n                (dim, collection_id),\n            )\n        elif stored != dim:\n            raise DimensionMismatchError(\n                f\"sqlite_exact collection {self._collection_name!r} expects \"\n                f\"embedding dimension {stored}, got {dim}\"\n            )\n\n    def _fts_available(self, cur) -> bool:\n        row = cur.execute(\"SELECT value FROM meta WHERE key = 'fts5_available'\").fetchone()","sourceCodeStart":321,"sourceCodeEnd":357,"githubUrl":"https://github.com/MemPalace/mempalace/blob/06cb6987f02610784fefbad4b2bd5d026d164ba6/mempalace/backends/sqlite_exact.py#L321-L357","documentation":"Raised by `_ensure_collection_dimension` during writes: a single upsert/add batch contains embeddings of two or more different dimensionalities. sqlite_exact enforces one embedding dimension per collection so cosine-similarity search stays meaningful; mixing dimensions in one batch is rejected before any row is inserted.","triggerScenarios":"Calling upsert with `embeddings` where vectors have differing lengths — e.g. some from a 384-dim model (MiniLM) and some from a 768/1536-dim model; rows with `None`/empty embeddings mixed with real ones in ways that decode to different sizes; concatenating batches produced under different embedder configs.","commonSituations":"Changing the local embedding model (Ollama/LM Studio model swap) between incremental ingest runs and then replaying old cached vectors together with new ones; an embedding cache keyed only by text, not by model; multi-source ingest where adapters use different embedders.","solutions":["Re-embed all vectors in the batch with one model so every vector shares a dimension, then retry the upsert.","Key your embedding cache by (text, model) so stale-dimension vectors are never reused after a model switch.","Split the batch by dimension and write each group to a differently-named collection (e.g. `drawers_384`, `drawers_1536`).","Check `get_stored_embedder_identity()` before writing to confirm the collection's model matches the current embedder."],"exampleFix":"# before\nembeddings = cached_old_vectors + [embed_new(d) for d in new_docs]  # 384 + 1536 mixed\ncol.upsert(ids=ids, documents=docs, embeddings=embeddings)\n\n# after\nembeddings = [embed_new(d) for d in all_docs]  # one model, one dimension\ncol.upsert(ids=all_ids, documents=all_docs, embeddings=embeddings)","handlingStrategy":"validation","validationCode":"def check_uniform_dimensions(embeddings, ids):\n    dims = {len(e) for e in embeddings}\n    if len(dims) > 1:\n        raise ValueError(f\"batch mixes dimensions {sorted(dims)}; re-embed with one model\")\n    return dims.pop() if dims else None","typeGuard":null,"tryCatchPattern":"try:\n    col.upsert(ids=ids, documents=docs, embeddings=embs)\nexcept DimensionMismatchError:\n    embs = [embed(d) for d in docs]  # one model, one dimension\n    col.upsert(ids=ids, documents=docs, embeddings=embs)","preventionTips":["Pin one embedding model per palace and record it via get_stored_embedder_identity().","Key embedding caches by (text, model_name) so cross-model vectors never mix.","After switching local models, re-embed everything instead of replaying cached vectors."],"tags":["sqlite-exact","embeddings","dimension-mismatch","ingest"],"backgroundTag":null,"analyzedSha":"06cb6987f02610784fefbad4b2bd5d026d164ba6","analyzedAt":"2026-08-15T03:03:36.213Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}