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-04-10Advanced

Gemini API Practical Troubleshooting Guide — Master 2.5 Pro Rate Limits, Timeouts & Errors

Systematically troubleshoot Gemini 2.5 Pro API errors: 429 rate limits, 504 timeouts, 400 validation errors, and Safety Filter blocks. Learn production-ready solutions with retry strategies, streaming optimization, and cost-saving techniques.

gemini-api277troubleshooting82gemini-2.5-pro13rate-limit4error-handling8

Premium Article

The night a 429 alert woke me up

One evening, the image-classification batch in one of the apps I build as an indie developer ground to a halt, throwing 429s in a cluster. Digging through the logs, I found that the requests I was firing in parallel had blown past the per-minute limit all at once. It took me the better part of an hour to see it. That stuck feeling is where this article starts.

Running Gemini API in production means you cannot avoid 429 (rate limits), 504 (timeouts), and 400 (validation) errors. But these are not a matter of bad luck. Once you understand how each one arises, most of them can be headed off on the architecture side, before they ever fire.

This is not about papering over errors with quick fixes. We start from the structure — why each error appears — and pair it with the implementation patterns I actually run in production, along with the numbers I measured along the way. The mindset is built to keep working even as the model underneath changes, such as gemini-flash-latest (currently backed by Gemini 3.5 Flash).

Error 1: 429 Too Many Requests (Rate Limit)

How it happens

Gemini API enforces rate limits on the number of API calls per minute and per day. Exceeding these limits returns a 429 error.

Rate limits vary by plan:

  • Free tier: 60 requests/hour, 15 requests/minute
  • Pro: 300 requests/minute, 1.5M requests/day

Root causes

  1. Too many concurrent requests: Multiple API calls executing simultaneously
  2. Unoptimized batch processing: Requests that should be grouped are sent separately
  3. Polling interval too short: Rapidly polling the same endpoint
  4. Multiple applications interfering: Different apps sharing the same API key

Implementation: Exponential Backoff + Retry Logic

async function callGeminiAPIWithRetry(
  prompt: string,
  maxRetries: number = 5,
  baseDelayMs: number = 1000
): Promise<string> {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const response = await fetch(
        'https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-pro:generateContent',
        {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'x-goog-api-key': process.env.GEMINI_API_KEY,
          },
          body: JSON.stringify({
            contents: [{ parts: [{ text: prompt }] }],
          }),
        }
      );
 
      if (response.status === 429) {
        // Rate limited: use exponential backoff
        const delayMs = baseDelayMs * Math.pow(2, attempt) + Math.random() * 1000;
        console.log(`Rate limited. Retrying after ${delayMs}ms (attempt ${attempt + 1}/${maxRetries})`);
        await new Promise(resolve => setTimeout(resolve, delayMs));
        continue;
      }
 
      if (response.ok) {
        const data = await response.json();
        return data.candidates[0]?.content?.parts[0]?.text || '';
      }
 
      throw new Error(`API Error: ${response.status}`);
    } catch (error) {
      if (attempt === maxRetries - 1) throw error;
      
      const delayMs = baseDelayMs * Math.pow(2, attempt);
      console.log(`Attempt ${attempt + 1} failed. Retrying in ${delayMs}ms...`);
      await new Promise(resolve => setTimeout(resolve, delayMs));
    }
  }
 
  throw new Error('Max retries exceeded');
}

Solution: Sequential processing and batch API

Combine multiple requests into one

// Poor: parallel execution
Promise.all([
  callGeminiAPI(prompt1),
  callGeminiAPI(prompt2),
  callGeminiAPI(prompt3),
]);
 
// Better: sequential processing
const prompts = [prompt1, prompt2, prompt3];
for (const prompt of prompts) {
  const result = await callGeminiAPIWithRetry(prompt);
}

Use Batch API

async function batchGenerateContent(prompts: string[]) {
  const requests = prompts.map(prompt => ({
    model: 'models/gemini-2.5-pro',
    contents: [{ parts: [{ text: prompt }] }],
  }));
 
  const response = await fetch(
    'https://generativelanguage.googleapis.com/v1beta/batch:generateContent',
    {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'x-goog-api-key': process.env.GEMINI_API_KEY,
      },
      body: JSON.stringify({ requests }),
    }
  );
 
  return response.json();
}

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
A design workflow that measures retry amplification as a hard number
A triage table separating 429, 503, 504, 400, and Safety from the first move
Production patterns that cut API call volume with caching, batching, and model routing
Secure payment via Stripe · Cancel anytime

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
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 →

Related Articles

API / SDK2026-06-12
Reverse-Engineering Empty Gemini API Responses with finish_reason — Triage, Retry Classification, and Monitoring
An empty response.text has three distinct failure layers — candidates, prompt_feedback, and finish_reason. Production code for detecting thinking-token starvation, classifying what is worth retrying, and monitoring your empty-response rate.
API / SDK2026-05-12
Gemini File API Stuck in PROCESSING State: Timeout Handling and Retry Design
Fix Gemini File API files stuck in PROCESSING state. Learn proper polling with exponential backoff, timeout design, and cleanup strategies with working Python code examples.
API / SDK2026-05-03
Why Gemini API Returns RECITATION as finish_reason — and How to Fix It
When Gemini API silently truncates responses with finish_reason RECITATION, the request technically succeeds with HTTP 200 — but the output is gone. Here's what actually triggers it and how to recover.
📚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 →