fix(oss): auto-detect embedding dimension to fix Qdrant mismatch with non-OpenAI embedders#4297
Merged
whysosaket merged 5 commits intomainfrom Mar 12, 2026
Merged
Conversation
… non-OpenAI embedders When using embedders like Ollama's nomic-embed-text (768 dims), the hardcoded 1536 default caused Qdrant to reject vectors with Bad Request. - Probe embedder at init to auto-detect dimension when not explicitly set - Defer vector store creation until dimension is known - Gate all public Memory methods behind lazy init promise - Fix Qdrant collection creation race condition (TOCTOU → atomic create + catch 409) - Fix Google embedder hardcoded outputDimensionality (768 → config value) - Use absolute path for default historyDbPath (~/.mem0/memory.db) - Propagate init errors to callers with clear message suggesting explicit config Fixes #4212, #4173, #4056 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ection - Make Qdrant.initialize() idempotent with promise gate to prevent double-init race between constructor and explicit callers - Make ensureCollection resilient to transient 500 errors during dimension verification after 409 - Await vectorStore.initialize() in Memory._autoInitialize() to guarantee collections exist before any public method runs - Add 8 e2e tests against real Qdrant verifying all three issues: dimension mismatch (#4212/#4173), race condition (#4056), and memory_migrations dimension isolation (#4056) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Prevent double-initialization when Memory explicitly calls initialize() after the constructor already fired it. Without this guard, Redis reconnects, Supabase re-verifies, AzureAISearch re-lists indexes, and Vectorize re-creates indexes on every call. Adds 13 Redis Stack e2e tests and 34 backward-compatibility unit tests covering all vector store implementations. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Member
|
Once init fails, the Memory instance is permanently dead... no retry, no recovery. If the embedder was briefly down at startup, user has to recreate everything. |
whysosaket
reviewed
Mar 11, 2026
Member
|
E2E tests hard-fail without local Qdrant/Redis and have no skip mechanism. |
whysosaket
previously approved these changes
Mar 11, 2026
- Log transient verification errors in ensureCollection instead of silently swallowing them (auth/network failures are now visible) - Auto-retry initialization on failure so a transiently unavailable embedder or vector store at startup doesn't permanently kill the Memory instance - Skip e2e tests gracefully when Qdrant/Redis containers aren't running Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
whysosaket
approved these changes
Mar 12, 2026
This was referenced Mar 12, 2026
Closed
This was referenced Mar 16, 2026
jamebobob
pushed a commit
to jamebobob/mem0-vigil-recall
that referenced
this pull request
Mar 29, 2026
… non-OpenAI embedders (mem0ai#4297) Co-authored-by: utkarsh240799 <utkarsh240799@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
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.
Problem
Users using non-OpenAI embedding providers (Ollama/nomic-embed-text, Google/Gemini, HuggingFace, etc.) hit
Bad Requesterrors when using Qdrant because the vector store was always created with a hardcoded default dimension of 1536 (OpenAI's dimension), regardless of the actual embedding model's output dimension.This caused three related issues:
Bad Requeston insertmemory_migrationscollection using wrong dimensionSolution
1. Probe-based dimension auto-detection
When no explicit dimension is provided, the
Memoryclass now embeds a short probe string ("dimension probe") at initialization time and reads the resulting vector length to determine the correct dimension. This happens before the vector store is created.Dimension resolution order:
vectorStore.config.dimension(user override)embedder.config.embeddingDims(embedder config)2. Deferred vector store creation
The vector store is no longer created in the
Memoryconstructor. Instead, it's created in an async_autoInitialize()method after the dimension is known. All public Memory methods (add,search,getAll, etc.) await initialization before proceeding via a lazy init gate (_ensureInitialized()).3. Atomic Qdrant collection creation
Replaced the check-then-create pattern (TOCTOU race) with create-and-catch-409:
4. Idempotent init guards for all vector stores
Every vector store with async initialization (Qdrant, Redis, Supabase, AzureAISearch, Vectorize) now uses a
_initPromisesingleton guard. This prevents double-initialization whenMemoryexplicitly callsawait vectorStore.initialize()after the constructor already fired it:Without this guard:
connect()→"Socket already opened", plusdropIndex/createIndexdestroys the index the first call just builtcreateCollection→409 Conflictcrashindexes.create()→ Cloudflare API error5. Google embedder fix
Fixed hardcoded
outputDimensionality: 768ingoogle.ts— now usesthis.embeddingDimsfrom config.Files Changed
src/oss/src/memory/index.tssrc/oss/src/config/manager.tssrc/oss/src/vector_stores/qdrant.tssrc/oss/src/vector_stores/redis.tssrc/oss/src/vector_stores/supabase.tssrc/oss/src/vector_stores/azure_ai_search.tssrc/oss/src/vector_stores/vectorize.tssrc/oss/src/embeddings/google.tsembeddingDimsconfig instead of hardcoded 768Testing
Unit Tests (61 tests)
dimension-autodetect.test.ts(22 tests) — ConfigManager dimension resolution, MemoryVectorStore backward compat, Memory auto-initialization, error propagationconfig-manager.test.ts(5 tests) — ConfigManager dimension priority chainvector-stores-compat.test.ts(34 tests) — Backward compatibility for all 7 vector store implementations (MemoryVectorStore, Qdrant, Redis, Supabase, AzureAISearch, Vectorize, Langchain) with mocked clientsEnd-to-End Tests (21 tests, against real instances)
qdrant-e2e.test.ts(8 tests) — Against real Qdrant v1.13.0:ensureCollectionrace condition (5 parallel instances)getUserId/setUserIdafter concurrent initmemory_migrationsuses dim=1 independently of main collectionredis-e2e.test.ts(13 tests) — Against real Redis Stack:getUserId/setUserIdroundtripTotal: 82 tests, all passing
Checklist
dimensionconfig still works, no probe triggered