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-30Intermediate

Why Gemini 2.5 Pro Rejects thinkingBudget: 0 (and How to Fix It)

Setting thinkingBudget to 0 on Gemini 2.5 Pro returns a 400 INVALID_ARGUMENT error. Here is why the per-model thinking budget ranges differ, how to minimize thinking on Pro the right way, and when to switch to Flash, with Python and JavaScript examples.

troubleshooting82error15fix10gemini-api277thinking7gemini-2-5-pro3python104

I'm Masaki Hirokawa, an artist and indie developer. I've been building mobile apps on my own since 2014. The other day, while wiring an in-app tagging feature for one of my wallpaper apps to Gemini 2.5 Pro, I wanted to shave off some latency and set thinkingBudget to 0. The whole generation call died with a 400 error. The exact same code worked fine on 2.5 Flash, so my first guess was an SDK bug.

It wasn't a bug. Gemini 2.5 Pro simply does not allow thinking to be turned off completely. The same thinking-budget setting accepts different value ranges depending on the model. Here's how to tell the symptom apart and write it correctly so you don't lose an afternoon to it like I almost did.

The symptom: thinkingBudget: 0 returns 400 INVALID_ARGUMENT

Here is the reproduction. In the Python SDK (google-genai), setting the thinking budget to 0 on Pro fails:

from google import genai
from google.genai import types
 
client = genai.Client(api_key="YOUR_GEMINI_API_KEY")
 
# Works on 2.5 Flash, but returns 400 on 2.5 Pro
resp = client.models.generate_content(
    model="gemini-2.5-pro",
    contents="Give me 5 tags that fit this description.",
    config=types.GenerateContentConfig(
        thinking_config=types.ThinkingConfig(thinking_budget=0),  # Pro rejects 0
    ),
)
print(resp.text)

The error you get back looks roughly like this:

google.genai.errors.ClientError: 400 INVALID_ARGUMENT
{
  "error": {
    "code": 400,
    "message": "Budget 0 is invalid. Expected a value in the range [128, 32768], or -1 (DYNAMIC) for models/gemini-2.5-pro.",
    "status": "INVALID_ARGUMENT"
  }
}

The key detail is that the message explicitly says 0 is invalid and that it expects [128, 32768] or -1. The API parsed your request correctly and rejected the value itself. This is not a malformed request or a network problem.

Why only Pro rejects 0 — the per-model thinking budget ranges

The Gemini 2.5 family lets you tune how many tokens go toward internal "thinking" via thinkingBudget. The accepted range, however, differs by model. As of this writing (May 2026), it breaks down roughly like this:

  • gemini-2.5-pro: 128 to 32,768 tokens, or -1 (dynamic allocation). Thinking cannot be fully disabled (0 is not allowed). Because it is built for hard reasoning, at least 128 tokens always go to thinking.
  • gemini-2.5-flash: 0 to 24,576 tokens. Passing 0 disables thinking entirely.
  • gemini-2.5-flash-lite: does not think by default. You can enable thinking by giving it a budget.

If you don't know about this difference and "reuse the setting that worked on Flash for Pro," you hit exactly this error. That's what happened to me: I prototyped on Flash, then swapped in Pro for smarter output in production, and it broke the moment I switched models. When you change models, you have to change the thinking-budget assumptions along with them.

Note that -1 means dynamic allocation, where the model decides how much thinking to spend based on task difficulty. If you just want a safe default on Pro, pass -1 instead of 0.

Fix 1: minimize thinking on Pro the right way

If you want to stay on Pro but trim the thinking overhead as much as possible, pass the minimum value of 128 instead of 0:

resp = client.models.generate_content(
    model="gemini-2.5-pro",
    contents="Give me 5 tags that fit this description.",
    config=types.GenerateContentConfig(
        thinking_config=types.ThinkingConfig(thinking_budget=128),  # smallest allowed budget
    ),
)
print(resp.text)
print("thinking tokens:", resp.usage_metadata.thoughts_token_count)

usage_metadata.thoughts_token_count tells you how many tokens were actually spent on thinking. Whether 128 is enough for your output quality is something you should judge from this value and from the actual responses. For lightweight work like tagging or short classification, I saw almost no perceptible quality drop at 128.

On the other hand, capping summarization consistency or multi-step reasoning at 128 can make the conclusions sloppy. Whenever you trim thinking for cost or speed, check a few output samples to confirm quality hasn't degraded.

Fix 2: switch to 2.5 Flash when speed and cost come first

Honestly, the moment you feel like you want to turn thinking off completely, that task is often overkill for Pro. Tagging, short classification, and reshaping text into a fixed format are all handled well by Flash with thinking disabled.

resp = client.models.generate_content(
    model="gemini-2.5-flash",
    contents="Give me 5 tags that fit this description.",
    config=types.GenerateContentConfig(
        thinking_config=types.ThinkingConfig(thinking_budget=0),  # Flash allows 0
    ),
)
print(resp.text)

I eventually moved my wallpaper app's tagging from Pro (128) to Flash (thinking off). Output quality was practically identical for my use, responses came back one or two seconds faster, and the token bill dropped by exactly the thinking portion that disappeared. Since I run these apps solo on mostly AdMob revenue, small savings like this add up.

As a rule of thumb: if you want speed and low cost over raw smarts, use Flash (thinking off if you like); if you need hard reasoning or code generation accuracy, use Pro (128 or higher, or -1).

A field-name trap in the migrated SDK: thinkingConfig

Around the same error, there's a second thing that trips people up: getting the field name wrong. In the new unified SDK (google-genai / @google/genai), the naming convention differs by language.

In JavaScript / TypeScript it is camelCase:

import { GoogleGenAI } from "@google/genai";
 
const ai = new GoogleGenAI({ apiKey: "YOUR_GEMINI_API_KEY" });
 
const res = await ai.models.generateContent({
  model: "gemini-2.5-flash",
  contents: "Give me 5 tags that fit this description.",
  config: {
    thinkingConfig: { thinkingBudget: 0 }, // camelCase in JS
  },
});
console.log(res.text);

There are two common mistakes. One is placing thinkingConfig at the top level instead of inside config, which makes the setting silently ignored. The other is mixing in the syntax of the old SDK (@google/generative-ai). If a setting doesn't seem to take effect, first check that thinkingConfig sits directly under config. Also remember that Python uses snake_case (thinking_config / thinking_budget) while REST uses camelCase (thinkingConfig / thinkingBudget) — the spelling changes by layer.

Prevention: keep per-model settings in one place

The real fix against recurrence is a single table that maps a model name to its thinking budget. If you stop hard-coding 0 at each call site, swapping models won't trigger this error again.

# Map each model to an allowed thinking budget
THINKING_BUDGET = {
    "gemini-2.5-pro": 128,         # 0 not allowed; clamp to the minimum
    "gemini-2.5-flash": 0,         # 0 disables thinking
    "gemini-2.5-flash-lite": 0,    # no thinking by default
}
 
def make_config(model: str):
    budget = THINKING_BUDGET.get(model, -1)  # unknown models fall back to dynamic (-1)
    return types.GenerateContentConfig(
        thinking_config=types.ThinkingConfig(thinking_budget=budget),
    )
 
resp = client.models.generate_content(
    model="gemini-2.5-pro",
    contents="Give me 5 tags that fit this description.",
    config=make_config("gemini-2.5-pro"),
)

Falling back to -1 (dynamic) for unknown model names means a newly released model won't crash with a 400 even if you forget to add it. I call Gemini through a shared library across several apps, so keeping this in one place saves me from patching every call site whenever a model updates.

The next time you see this error, read the Expected a value in the range [...] part of the message first, and check whether the model you're using allows 0 (the Flash family) or not (Pro). That single check resolves most cases.

Reference: Gemini API official docs — Thinking

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-04-14
Veo API Not Working? Common Errors and How to Fix Them
Troubleshoot common Veo API errors including polling implementation mistakes, safety filter rejections, quota exceeded, and video file download failures. With working Python code examples.
API / SDK2026-04-08
Gemini API 503 Service Unavailable Error: Causes, Fix, and Retry Implementation
Learn why Gemini API returns 503 Service Unavailable errors and how to fix them with exponential backoff retry logic. Includes ready-to-use Python and JavaScript code examples.
API / SDK2026-04-07
Gemini API SDK Version Mismatch & Install Errors: How to Fix Them
A step-by-step troubleshooting guide for Gemini API SDK install failures and version mismatch errors in Python and Node.js projects.
📚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 →