GEMINI LABJP
NANOLITE — Nano Banana 2 Lite is here: Google's fastest and most cost-efficient Gemini Image model, made for running lightweight image generation cheaplyOMNIFLASH — Gemini Omni Flash is in public preview, a natively multimodal model that lets enterprises and developers build custom, dynamic video workflowsAGENTS — Managed Agents expand with background: true for async server-side runs and polling, remote MCP server integration, and refreshing credentials across interactionsMEMORY — The Memory Bank IngestEvents API is generally available, decoupling event ingestion from memory generation so you can stream content continuouslyTHROUGHPUT — Provisioned Throughput now lets you submit up to seven pending orders for the same model and regionDEPRECATE — Image generation models shut down on August 17, and the Grok 4.1 family on the Gemini Enterprise Agent Platform on August 20NANOLITE — Nano Banana 2 Lite is here: Google's fastest and most cost-efficient Gemini Image model, made for running lightweight image generation cheaplyOMNIFLASH — Gemini Omni Flash is in public preview, a natively multimodal model that lets enterprises and developers build custom, dynamic video workflowsAGENTS — Managed Agents expand with background: true for async server-side runs and polling, remote MCP server integration, and refreshing credentials across interactionsMEMORY — The Memory Bank IngestEvents API is generally available, decoupling event ingestion from memory generation so you can stream content continuouslyTHROUGHPUT — Provisioned Throughput now lets you submit up to seven pending orders for the same model and regionDEPRECATE — Image generation models shut down on August 17, and the Grok 4.1 family on the Gemini Enterprise Agent Platform on August 20
Articles/API / SDK
API / SDK/2026-05-15Intermediate

3 Gemini API Embedding Errors I Hit Building a Wallpaper App — and How I Fixed Them

Three real Gemini API Embedding errors encountered while building an auto-categorization feature for a wallpaper app with 50M+ downloads: INVALID_ARGUMENT, RESOURCE_EXHAUSTED 429, and poor RAG precision — with working code fixes.

Gemini API192Embedding3RAG14error15Python38indie developer12troubleshooting82

When I integrated Gemini API Embedding into the backend of Beautiful HD Wallpapers — an iOS/Android wallpaper app with over 50 million cumulative downloads — I ran into three distinct problems in quick succession. The sample code from the official docs worked fine for a handful of items, but as soon as I tried to process hundreds of wallpaper descriptions in a real pipeline, things started breaking.

Here's what went wrong and how I fixed each issue.

INVALID_ARGUMENT — output_dimensionality Mismatch with Existing Index

The text-embedding-004 model returns 768-dimensional vectors by default, but you can change this with the output_dimensionality parameter. The problem: if you change it after you've already built a ChromaDB index at a different dimension, you'll get INVALID_ARGUMENT on every request.

I made this mistake by initially creating an index at 3,072 dimensions, then trying to switch to 768 to save costs.

import google.generativeai as genai
 
genai.configure(api_key="YOUR_GEMINI_API_KEY")
 
# ❌ This breaks if your existing index was built at 3072 dimensions
result = genai.embed_content(
    model="models/text-embedding-004",
    content="Beautiful mountain landscape",
    output_dimensionality=768,  # Mismatches the existing index
)
 
# ✅ Fix: align with your existing index, or rebuild it
result = genai.embed_content(
    model="models/text-embedding-004",
    content="Beautiful mountain landscape",
    output_dimensionality=3072,  # Match whatever your index was built with
)

Think of output_dimensionality as something you decide once at index creation time, not a dial you can turn later. If you want to switch dimensions, you'll need to rebuild the index from scratch with the new setting. In my case, rebuilding with 768 dimensions was worth it for the long-term cost savings.

RESOURCE_EXHAUSTED (429) — Batch Processing Hits Rate Limits Fast

Trying to embed 500 wallpaper descriptions in one go triggered a continuous stream of RESOURCE_EXHAUSTED errors. The Gemini API Embedding endpoint has per-minute call limits that become a real constraint when you're doing bulk processing.

Exponential backoff solved it:

import time
import google.generativeai as genai
 
def embed_with_backoff(content: str, max_retries: int = 5) -> list[float]:
    """Embedding call with exponential backoff for rate limit handling."""
    for attempt in range(max_retries):
        try:
            result = genai.embed_content(
                model="models/text-embedding-004",
                content=content,
                task_type="RETRIEVAL_DOCUMENT",
            )
            return result["embedding"]
        except Exception as e:
            if "429" in str(e) or "RESOURCE_EXHAUSTED" in str(e):
                wait_sec = 2 ** attempt  # 1, 2, 4, 8, 16 seconds
                print(f"Rate limit hit. Waiting {wait_sec}s (attempt {attempt + 1})")
                time.sleep(wait_sec)
            else:
                raise  # Re-raise anything that isn't a rate limit error
 
    raise RuntimeError("Max retries exceeded")
 
 
# Example: batch processing with interval
descriptions = ["Mountain landscape", "Ocean sunset", "City skyline at night"]
embeddings = []
for desc in descriptions:
    emb = embed_with_backoff(desc)
    embeddings.append(emb)
    time.sleep(1.0)  # 1-second interval recommended for production

A 100ms interval wasn't enough — I settled on 1 second between calls plus the backoff. For large batches, running the job during off-peak hours also helps a lot.

Poor RAG Precision — task_type Was Missing

After getting the Embedding pipeline running without errors, the search results still felt off. Relevant wallpapers weren't surfacing when they should have been. The culprit was a missing task_type parameter.

Gemini's Embedding model generates different vector spaces depending on the intended use case. For retrieval tasks, you need to distinguish between query vectors and document vectors:

# ❌ No task_type — model uses a generic embedding space
result = genai.embed_content(
    model="models/text-embedding-004",
    content="Looking for a natural wallpaper",
)
 
# ✅ For search queries, use RETRIEVAL_QUERY
query_result = genai.embed_content(
    model="models/text-embedding-004",
    content="Looking for a natural wallpaper",
    task_type="RETRIEVAL_QUERY",  # For incoming search queries
)
 
# ✅ For documents being indexed, use RETRIEVAL_DOCUMENT
doc_result = genai.embed_content(
    model="models/text-embedding-004",
    content="Sunlight filtering through green forest leaves",
    task_type="RETRIEVAL_DOCUMENT",  # For items stored in your index
)

Switching to the correct task_type improved cosine similarity-based search precision by roughly 15–20% in my testing. If you've already built an index without task_type, you'll need to regenerate all document vectors and rebuild the index.

The Configuration That Worked in Production

After working through all three issues, here's what I lock in from the start on any new Embedding integration:

# Embedding config used in wallpaper app backend
EMBEDDING_CONFIG = {
    "model": "models/text-embedding-004",
    "output_dimensionality": 768,      # Decide once, never change
    "query_task_type": "RETRIEVAL_QUERY",
    "doc_task_type": "RETRIEVAL_DOCUMENT",
    "batch_interval_sec": 1.0,         # 1-second gap between calls in production
    "max_retries": 5,                  # Exponential backoff up to 5 attempts
}

Fix the dimension at the start, use the right task_type for queries vs. documents, and build in retry logic from day one. With those three things in place, Gemini Embedding API is genuinely practical for indie developer projects — even at the scale of a production mobile app.

Where to Start

If you're hitting any of these issues right now, the lowest-effort fix is adding task_type. It's a one-line change that doesn't require rebuilding your index, and it often makes a noticeable difference in retrieval quality. Start there, then address dimension alignment and rate limiting as needed.

As an indie developer who has been building mobile apps since 2014, I've learned that most Embedding integration issues come down to configuration decisions made too early — or not made at all. Getting them right upfront saves a lot of debugging time later.

A Note on Model Selection

Beyond text-embedding-004, there are experimental models like gemini-embedding-exp-03-07 that often score higher on benchmarks. In production, I've stayed with the stable model because experimental ones can change behavior without notice — which is a real problem when you've built an index with thousands of embeddings and need consistent vector spaces.

Switching models after the fact means regenerating every document embedding from scratch and rebuilding the index. This is the same fundamental issue as changing output_dimensionality: both decisions are tightly coupled to your index, not just to your API call. Make these choices once, early, before you've accumulated data.

Improving RAG Precision Further

After fixing task_type, I kept experimenting with ways to improve search quality in the wallpaper app. Two things made a noticeable difference.

First, embedding richer descriptions rather than just category names. Instead of embedding the word "nature," embedding "wallpapers featuring mountains, forests, lakes, and open skies" gave much better cosine similarity scores against actual search queries.

Second, preprocessing search queries before embedding them. Users type short, varied search terms. Running a quick Gemini API prompt to expand those terms into a short descriptive sentence before embedding them stabilized precision meaningfully. This is now a standard part of the wallpaper app's search pipeline.

Gemini Embedding API is genuinely solid once the configuration is right. The three errors I described are frustrating precisely because they're silent or vague — but once you know what to look for, they're straightforward to fix.

Share

Thank You for Reading

Gemini Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • Copy-paste ready implementation code
  • New advanced guides published daily
  • $5/mo or $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

API / SDK2026-05-11
Gemini 3.2 API Suddenly Broke — 5 Common Errors and How to Fix Them
Switched to Gemini 3.2 API and hit a wall? This guide covers 5 common errors developers encounter during migration — wrong model IDs, rate limits, context overflow, streaming interruptions, and Function Calling schema failures — with working code fixes.
API / SDK2026-05-05
Choosing the Right Gemini RAG Pattern in 2026 — Simple vs Advanced vs Agentic, Compared with Real Code
Compare three RAG implementation patterns with the Gemini API — Simple, Advanced, and Agentic — using real code examples. Learn which pattern fits your use case and where to start.
API / SDK2026-03-29
Gemini API Authentication Errors: Causes and Solutions
Complete guide to diagnosing and fixing Gemini API authentication errors including 401/403 status codes, API key issues, and permissions.
📚RECOMMENDED BOOKS
Build a Large Language Model (From Scratch)
Sebastian Raschka
LLM Dev
Prompt Engineering for LLMs
Berryman & Ziegler
Prompting
AI Engineering
Chip Huyen
AI Eng
* Contains affiliate links
See all →