Troubleshooting: Gemini Embedding Model Returns Empty Vectors in LangChain.js

Fengyu

When indexing documents and storing the resulting vectors in our vector database (PostgreSQL + pgvector), we occasionally encountered the following error:

error: vector must have at least 1 dimension
...
routine: 'vector_in'

The indexing pipeline consists of:

  • langchain.js
  • gemini-embedding-001 (free tier)
  • pgvector

This issue didn’t occur every time, but it would suddenly appear when everything seemed to be working correctly. This behavior was frustrating, so I decided to investigate the root cause.

Analysis

The error message hinted I was receiving empty vectors, which I could verify with the following code:

const vectors = await embeddings.embedDocuments(
  documents.map((doc) => doc.pageContent)
);
console.log(vectors);

The log output was:

[
  [], [], [], [], [], [], [], [],
  ... // empty vectors
]

In the source code of GoogleGenerativeAIEmbeddings, I found all returned exceptions were replaced with empty vectors. This explains why empty vectors were silently returned.

const batchEmbedRequests = batchEmbedChunks.map((chunk) => ({
  requests: chunk.map((doc) => this._convertToContent(doc)),
}));

const responses = await Promise.allSettled(
  batchEmbedRequests.map((req) => this.client.batchEmbedContents(req))
);

const embeddings = responses.flatMap((res, idx) => {
  if (res.status === "fulfilled") {
    return res.value.embeddings.map((e) => e.values || []);
  } else {
    return Array(batchEmbedChunks[idx].length).fill([]); // <-- here
  }
});

However, I still did not know the actual error messages returned by Gemini, so I vibed the following method to help me:

function attachGenAIDebug(embeddings: any) {
  const client = embeddings?.client;
  if (!client) return;

  for (const method of ["batchEmbedContents", "embedContent"] as const) {
    if (typeof client[method] !== "function") continue;

    const orig = client[method].bind(client);
    client[method] = async (req: any) => {
      const meta =
        method === "batchEmbedContents"
          ? {
              requests: req?.requests?.length,
              totalChars: (req?.requests ?? []).reduce(
                (s: number, r: any) =>
                  s + (r?.content?.parts?.[0]?.text?.length ?? 0),
                0
              ),
            }
          : { chars: req?.content?.parts?.[0]?.text?.length ?? 0 };

      try {
        const res = await orig(req);
        const dims =
          res?.embedding?.values?.length ??
          res?.embeddings?.[0]?.values?.length ??
          0;
        console.error(`[genai] ${method} OK`, meta, { dims });
        return res;
      } catch (err) {
        console.error(`[genai] ${method} FAIL`, meta, err);
        throw err;
      }
    };
  }
}

Then I used it to intercept the error messages:

const embeddings = new GoogleGenerativeAIEmbeddings();
attachGenAIDebug(embeddings);
const vectors = await embeddings.embedDocuments(
  documents.map((doc) => doc.pageContent)
);

Here was what I got:

[genai] batchEmbedContents FAIL { requests: 100, totalChars: 49929 } GoogleGenerativeAIFetchError: [GoogleGenerativeAI Error]: Error fetching from https://generativelanguage.googleapis.com/v1beta/models/gemini-embedding-001:batchEmbedContents: [429 Too Many Requests] You exceeded your current quota, please check your plan and billing details. For more information on this error, head to: https://ai.google.dev/gemini-api/docs/rate-limits. To monitor your current usage, head to: https://ai.dev/usage?tab=rate-limit.
* Quota exceeded for metric: generativelanguage.googleapis.com/embed_content_free_tier_requests, limit: 100, model: gemini-embedding-1.0
Please retry in 20.088593563s. [{"@type":"type.googleapis.com/google.rpc.Help","links":[{"description":"Learn more about Gemini API quotas","url":"https://ai.google.dev/gemini-api/docs/rate-limits"}]},{"@type":"type.googleapis.com/google.rpc.QuotaFailure","violations":[{"quotaMetric":"generativelanguage.googleapis.com/embed_content_free_tier_requests","quotaId":"EmbedContentRequestsPerMinutePerUserPerProjectPerModel-FreeTier","quotaDimensions":{"location":"global","model":"gemini-embedding-1.0"},"quotaValue":"100"}]},{"@type":"type.googleapis.com/google.rpc.RetryInfo","retryDelay":"20s"}]
    at handleResponseNotOk
{
  status: 429,
  statusText: 'Too Many Requests',
  errorDetails: [
    { '@type': 'type.googleapis.com/google.rpc.Help', links: [Array] },
    {
      '@type': 'type.googleapis.com/google.rpc.QuotaFailure',
      violations: [Array]
    },
    {
      '@type': 'type.googleapis.com/google.rpc.RetryInfo',
      retryDelay: '20s'
    }
  ]
}
[genai] batchEmbedContents OK { requests: 42, totalChars: 25856 } { dims: 3072 }
[
  [], [], [], [], [], [], [], [], [], [], [], [],
  [], [], [], [], [], [], [], [], [], [], [], [],
  [], [], [], [], [], [], [], [], [], [], [], [],
  [], [], [], [], [], [], [], [], [], [], [], [],
  [], [], [], [], [], [], [], [], [], [], [], [],
  [], [], [], [], [], [], [], [], [], [], [], [],
  [], [], [], [], [], [], [], [], [], [], [], [],
  [], [], [], [], [], [], [], [], [], [], [], [],
  [], [], [], [],
  ... 42 more items
]

That’s it, a 429 status code!

Solution

Before fixing the ratelimit issue, I had tried the following approaches:

  • maxRetries, not help, because all exceptions were swallowed.
  • maxBatchSize, no way to adjust it

Finally, I found a way: batchSize in the index method:

import { index as langchainIndex } from "@langchain/core/indexing";

const result = await langchainIndex({
  docsSource: documents,
  recordManager,
  vectorStore,
  options: {
    cleanup: "full",
    sourceIdKey: "source",
    batchSize: 10,
  },
});

This is not a perfect solution, but it does mitigate the issue. With manual retries, all documents embedding can be generated successfully.