TypeScript: Gemini Embedding 2 batches collapse to one vector and lose memories
Component
TypeScript SDK
Summary
GoogleEmbedder.embedBatch() passes a string array as contents to @google/genai. For gemini-embedding-2, the SDK normalizes that array into one multipart content item and the API returns one combined vector, not one vector per text. Mem0 then assigns undefined to subsequent memory embeddings, causing failed vector inserts. The first memory can also receive a combined embedding instead of its own.
The implementation remains unchanged on upstream main 94c3fe9 (SDK package 3.3.1).
Steps to Reproduce
With a Google API key, compare these requests using @google/genai:
import { GoogleGenAI } from "@google/genai";
const ai = new GoogleGenAI({ apiKey: process.env.GOOGLE_API_KEY });
const texts = ["Apples are fruit.", "The sky is blue."];
for (const contents of [texts, texts.map(text => ({ parts: [{ text }] }))]) {
const response = await ai.models.embedContent({
model: "gemini-embedding-2",
contents,
});
console.log(response.embeddings.length);
}
// Observed: 1, then 2GoogleEmbedder.embedBatch(texts) currently uses the first request shape. An inferred Memory.add() extracting multiple facts can then log:
Failed to insert memory <id>: TypeError: Cannot read properties of undefined (reading 'length')Expected Behavior
One separate embedding per input text, in order. Invalid/short embedding responses should be rejected so the existing per-text fallback can run.
Actual Behavior / How Verified
An AI coding agent ran live embedding-only requests with two harmless texts, then exercised the installed Memory.addToVectorStore and MemoryVectorStore against isolated in-memory SQLite, with controlled extraction and embedding responses. No existing memories were modified.
Actual live output:
{"inputTexts":2,"returnedEmbeddings":1,"dimensions":[3072]}
{"inputTexts":1,"returnedEmbeddings":1,"dimensions":[3072]}
{"model":"gemini-embedding-2","format":"explicit content objects","inputTexts":2,"returnedEmbeddings":2,"dimensions":[3072,3072]}
{"model":"gemini-embedding-001","format":"old model control","inputTexts":2,"returnedEmbeddings":2,"dimensions":[3072,3072]}Isolated insertion results:
- Two extracted memories + one embedding: 2 returned ADD results, 2 ADD history entries, 1 actual stored vector, and the exact
.lengtherror. - Two extracted memories + two embeddings: 2 results, 2 history entries, 2 stored vectors, no insert errors.
The history/result false-success behavior is a related core issue: insertion errors are caught but all records are still included in history/results. A focused Google-embedder patch can prevent this trigger; it should not claim to fix arbitrary vector-store insertion failures.
Environment
- Runtime mem0ai: 3.1.7; same Google embedder code on upstream main (3.3.1)
- @google/genai: 2.21.0
- Node: 24.18.0
- OS: Linux
- Model: gemini-embedding-2
What Was Ruled Out
Credentials and single-text requests work. The same two-string request returns two embeddings with gemini-embedding-001. SQLite successfully stores both records when given both vectors. This is not user/project scoping.
Proposed Fix
Send separate Content objects for batch texts and validate response cardinality and missing/empty vectors before returning. Keep the existing model and stored data unchanged. Add mocked regressions for aggregation and malformed responses.
AI Assistance
AI found and wrote this, and I have not reproduced it myself. The agent ran the probes and will disclose automated verification separately from human review. Requesting maintainer acceptance before a review-ready PR.
Source: mem0ai/mem0