◉GEMINI LABJP
●ARGON — gemini-4-argon is generally available as of 10/13, aimed at complex coding, agents, math and science●DEEP RES — deep-research-pro-preview-12-2025 shuts down 10/23, 6 days left. Move to deep-research-preview-04-2026●NANO — gemini-nano-banana-2.1 is GA (10/06). gemini-3.1-flash-image is deprecated with no shutdown date yet●MCP — One write-up cut an 85,000-token tool result to 310 tokens by wrapping it in an ADK FunctionTool●FLASH — gemini-3.7-flash and 3.5-flash now route automatically to newer Flash models (10/08)●NEW — Stop Re-Reading Every Crash Report: Gre…●ARGON — gemini-4-argon is generally available as of 10/13, aimed at complex coding, agents, math and science●DEEP RES — deep-research-pro-preview-12-2025 shuts down 10/23, 6 days left. Move to deep-research-preview-04-2026●NANO — gemini-nano-banana-2.1 is GA (10/06). gemini-3.1-flash-image is deprecated with no shutdown date yet●MCP — One write-up cut an 85,000-token tool result to 310 tokens by wrapping it in an ADK FunctionTool●FLASH — gemini-3.7-flash and 3.5-flash now route automatically to newer Flash models (10/08)●NEW — Stop Re-Reading Every Crash Report: Gre…
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-api286troubleshooting87gemini-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-04-09
Classify Gemini API Errors by Status — Handling 429, SAFETY, and Token Limits in Production
Sort Gemini API failures along two axes — HTTP status and finish_reason — so you know instantly whether to wait or to fix. Covers the three distinct 429 limits, model-deprecation fallbacks, and how the exception hierarchy changes after moving to the google-genai SDK.
◈ API / SDK2026-10-16
The Day /models Returns 200 but generateContent Returns 403 — Decide Your Triage Order Before It Happens
A triage order for the case where listing models succeeds with 200 but generation fails with 403 permission_denied. Includes a small diagnostic script that checks key, project, and billing in turn, why you should not retry a 403, and how to assemble what support needs.
◈ API / SDK2026-05-20
Gemini API Streaming Works Locally but Buffers in Production — Fixing Cloud Run, Vercel, and Cloudflare
Streaming responses flow token-by-token in local dev, then arrive as one big blob in production. A walkthrough of the five most common causes — Cloud Run timeouts, Vercel runtime mismatch, Cloudflare Workers proxying, server-side text() pitfalls, and client-side decoding — with the fixes I use on my own sites.