Repository navigation
Description
Three different issues make the thinking models (2.5 flash and pro) unreliable:
- The
thinking_budgetappears to be ignored. We get non-zero (and large)thoughts_token_countvalues regardless of thethinking_budgetconfig. This appears to be a known issue? - A
MAX_TOKENSfinish reason appears to be given ifthoughts_token_count + output_token_count > max_output_tokens. This is problematic since we don't appear to have proper control overthoughts_token_countright now. - If
MAX_TOKENSfinish reason is triggered, the response text is empty, making debugging of the above very difficult (we can't get a sense of the size of the output text).
We only started experiencing consistent MAX_TOKENS responses sometime last week, so it seems something might have changed recently? Either the default thinking budget, or the way max_output_tokens is applied?
The only solution that currently works for us is to set max_output_tokens=None, but then the thinking tokens often increase to ~6k even for very simple tasks.
Edit: we have only seen this occur when using structured output. I'm can't confirm if it occurs for unstructured output.
Environment details
- Programming language: Python
- OS: Ubuntu 22.04
- Language runtime version: 3.10
- Package version: 1.14.0
Example
The docs suggest setting thinking_budget=0 will turn thinking off, however with the following request:
class RelevantDataFields(BaseModel):
fields: List[Literal[tuple(field_names)]]
model_config = GenerateContentConfig(
system_instruction=self.system_instruction,
thinking_config=ThinkingConfig(thinking_budget=0),
max_output_tokens=2000,
temperature=0.,
response_schema=RelevantDataFields.model_json_schema(),
response_mime_type='application/json'
)
pred = await aio.models.generate_content(
model='gemini-2.5-pro-preview-03-25',
contents=prompt,
config=model_config
)the response is:
GenerateContentResponse(candidates=[Candidate(content=Content(parts=[Part(video_metadata=None,
thought=None, code_execution_result=None, executable_code=None, file_data=None, function_call=None,
function_response=None, inline_data=None, text='')], role='model'), citation_metadata=None,
finish_message=None, token_count=None, finish_reason=<FinishReason.MAX_TOKENS: 'MAX_TOKENS'>,
avg_logprobs=None, grounding_metadata=None, index=0, logprobs_result=None, safety_ratings=None)],
create_time=None, response_id=None, model_version='models/gemini-2.5-pro-preview-05-06',
prompt_feedback=None,
usage_metadata=GenerateContentResponseUsageMetadata(cache_tokens_details=None,
cached_content_token_count=None, candidates_token_count=None, candidates_tokens_details=None,
prompt_token_count=1674, prompt_tokens_details=[ModalityTokenCount(modality=<MediaModality.TEXT: 'TEXT'>, token_count=1674)], thoughts_token_count=2000, tool_use_prompt_token_count=None, tool_use_prompt_tokens_details=None, total_token_count=3674, traffic_type=None), automatic_function_calling_history=[], parsed=None)The thoughts_token_count=2000 despite setting thinking_budget=0, and the model version is also wrong (05-06 instead of 03-25).
Ideal solution
thinking_budgetshould constrainthoughts_token_countMAX_TOKENSfinish reason should only be returned if the number of output tokens is greater thanmax_output_tokens, rather than including the thinking budget (assuming this is the case?).- The computed output so far should be returned if
MAX_TOKENSis reached.
Activity
[-]Gemini 2.5 pro thinking budget and model version ignored[/-][+]Thinking models are unreliable when `max_output_tokens` set due to them ignoring the thinking budget[/+]ascillitoe commentedon May 8, 2025
Update: I've just noticed when I get
FinishReason.MaxTokens,thoughts_token_count = max_output_tokens, so the thought tokens definitely appear to be linked to the output token limit now? For example below is a response withmax_output_tokens=5000andthinking_budget=0:This is for a task that, before last week, ran very reliably with
max_output_tokens=500ongemini-2.5-pro-preview-03-25, so something has changed recently.sararob commentedon May 8, 2025
Thank you for this feedback, I've passed it along to the API team and will let you know when we have an update.
ascillitoe commentedon May 8, 2025
Thanks @sararob. Just as an FYI, I missed out a small but potentially important bit of information earlier. We've only seen this issue occur when using structured output. I've updated my initial post to mention this.
MiguelLopezVirues commentedon May 13, 2025
Hi, I have the same problem here, using the response_mime_type = "text/plain". I hit the MAX.TOKEN limit due to the thoughts_token_count.
Below the
response.model_dump()(Note that here I do not limit the output tokens, so the limit is effectively 65536):aeneaswiener commentedon May 16, 2025
We noticed this too. thinking_budget appears to be respected in AI Sduio, but not to the same way on the SDK here
To reproduce, run prompt
with thinking_budget 0, 50, 1000, 2000
It is perfectly respected in AI Studio for all these values
Gen AI SDK only respects 0, 1000, 2000, but when setting to 50, the actual thinking tokens used are closer to 1000 (for the same prompt that works fine in AI Sdudio
aeneaswiener commentedon May 16, 2025
Update, i have realised this issue is due to the authentication used. Token budget is respected when using API key auth, and is not respected when using vertex authentication with service default creds.
To reproduce
ascillitoe commentedon May 16, 2025
That is strange, we use
api_keyand consistently don't get thethinking_budgetrespected withgemini-2.5-pro-preview. The problem is bad enough for us that we've had to migrate to other providers for now.ascillitoe commentedon May 21, 2025
Hi @sararob , has the API team made any progress on this?
pamorgan commentedon May 21, 2025
API team addressed some of the raised concerns with include_thoughts and thinking_budget=0.
Please refer to documentation in https://ai.google.dev/gemini-api/docs/thinking and example in https://github.com/google-gemini/cookbook/blob/main/quickstarts/Get_started_thinking.ipynb
Please let us know if the issue persisted.
ascillitoe commentedon May 21, 2025
Hi @pamorgan we just tried again, we still have the same problem as before with structured generation and
gemini-2.5-pro-preview-05-06. We setthinking_budget=0, but we always get an empty response because we run out of output tokens (sincethoughts_token_count = max_output_tokens).MiguelLopezVirues commentedon May 21, 2025
In addition to the whole concern of gemini-2.5-flash not respecting thinking budgets, there's the fact that thoughts-token-counts are not included within the outputs field of the response object. If that is the case, even with issues respecting thought-budget we shouldn't be bumping into MAX.TOKENS problem. I believe to have seen documentation that supports my statement.
Additionally, thought-budget allows 24k tokens max, so the responses shouldn't in any case surpass that up to the 65k output limit. That must mean that even fixed internal limits are not respected :/
Anyway, thank you very much for the support @pamorgan @sararob :)
44 remaining items
b-antosik-marcura commentedon Feb 12, 2026
I have similar issue, did anyone found some workaround?
feat(settings): retire thinking_budgets — Gemini SDK ignores it (issue …
feat(settings): retire thinking_budgets — Gemini SDK ignores it (issue …
dewly-dat commentedon Jul 8, 2026
I'm also seeing this issue. Getting MAX_TOKENS with no response even after significantly reducing the thinking_level configuration.
fix: disable Gemini thinking — it was eating the output budget and
fix: disable Gemini thinking — it was eating the output budget and
fix: disable Gemini thinking — it was eating the output budget and
fix: disable Gemini thinking — it was eating the output budget and
cnpierrepapi commentedon Aug 22, 2026
Someone asked upthread whether anyone found a workaround. We did, and there is a number in it that
might save the next person a day.
Short version: on 3.5-flash the thinking spend has a floor of roughly two to three thousand tokens
before a single character of answer gets written. So any
max_output_tokensunder about 4k is nota small budget, it is a zero budget. It looks generous if you are thinking about the size of your
answer, which is what everybody does.
What it looked like for us
We ask for six short fields off a web page. Course fee, start date, duration, entry requirements,
plus two quotes. The answer is maybe 400 characters of JSON. 2048 felt like plenty.
Every single call came back
MAX_TOKENSwith 146 characters of text. Not most. Every one, acrossabout 400 pages.
The 146 characters are the tell, and they are why point 3 in the original report matters so much.
You do not get an empty response, you get a plausible looking fragment, so the first thing you
suspect is your prompt or your schema. We went and rewrote the prompt. Then the parser. Neither
was wrong.
Raised the same call to 8192 and it worked on the first try. Same prompt, same model, same pages.
Four of five pages returned a fee, five of five returned a start date, where the identical run at
2048 had returned nothing at all.
The bit that cost us the most
We had already been bitten by this months earlier, in a different call, and did not recognise it
the second time. That is worth saying out loud because it is the actual failure mode of this bug.
First time round, a longer answer got truncated mid object and
json.loadsraised. The error welogged said "the response was not JSON" and printed the first 160 characters, which sends you
looking at your schema.
finishReason: MAX_TOKENSwas sitting in the same response and nothingread it.
So the fix that helped most was not a bigger budget. It was reading the finish reason and saying
which failure it actually was:
Once the message said "cut off at the token limit after 146 characters" instead of "not JSON", the
second occurrence took two minutes instead of an afternoon.
What would actually help
Point 3 in the original report is the one I would push on. When
thoughts_token_counteats thebudget, the caller gets a truncated fragment and a finish reason they have to go looking for.
Anything that surfaces it at the point of failure would fix the debugging cost even while the
underlying budget behaviour stays as it is.
Two things that would have saved us:
thoughts_token_countis a large fraction ofmax_output_tokenswould be hard to ignore.configuration, it is a guaranteed failure, and the library could say so at call time rather than
after the round trip.
Neither needs the thinking budget itself to become controllable, which I gather is the harder half.
Environment:
gemini-3.5-flashon Vertex, REST,google-genai2.x. Happy to supply the failingcall and the exact response bodies if that is useful.
Size the Gemini output ceiling from Google's own reported behaviour
OSAC-4741: Fix empty/truncated Gemini responses, retry for a real ans…
madhu19991 commentedon Sep 25, 2026
Server-side repro on gemini-3.7 and 3.8 flash: thinking pushes total output to about 2x max_output_tokens. Details: https://discuss.ai.google.dev/t/gemini-3-8-flash-high-does-maxoutputtokens-include-thinking-tokens/181077
mjgweb-code commentedon Oct 1, 2026
We hit the same symptom this thread describes (
MAX_TOKENSfinish reason, truncated/empty-looking output, thinking tokens eating the whole budget) building a voice assistant ongemini-3.6-flash, called directly via the REST API rather than this SDK — but since the underlying API behavior should be the same, here's a confirmed-working fix plus real before/after numbers, in case it saves someone the day@cnpierrepapimentioned above.Our case: short, complete spoken replies with a tight
maxOutputTokens(200, since a voice reply needs to be brief anyway) and latency actually matters (it's a live conversation, not a batch job).MAX_TOKENSthinkingBudget: 0STOPthinkingLevel: "low"MAX_TOKENS(on the longer prompt)thinkingLevel: "minimal"STOPFor us,
thinkingBudget: 0wasn't "ignored" the way a few people above describe — it genuinely zeroed the thought-token spend and fixed the truncation outright, on this model. One nuance worth flagging for anyone reaching forthinkingLevelinstead:"low"is not the same as off — it still burned meaningful thought tokens and still hitMAX_TOKENSon the longer of our two test prompts. OnlythinkingBudget: 0orthinkingLevel: "minimal"fully eliminated it for us.Practical takeaway for anyone in a similar spot (tight, fixed output budget, don't need thinking for simple requests): if raising
max_output_tokensto absorb the thinking spend isn't attractive (ours is latency-sensitive — every token of thinking is time a user is waiting mid-conversation), settingthinkingBudget: 0cut our time-to-first-token roughly 2.5–3x on top of fixing the truncation. And whatever the fix, always logfinishReason— aMAX_TOKENStruncation can look like a plausible, if short, complete answer if you're not checking for it (point 3 in the original report, which cost us some debugging time too before we started logging it).I work with an AI coding assistant (Claude, Anthropic) on this project — it helped research and verify this finding and drafted this comment; I own the project, ran the real tests, and made the actual calls on what's reported here.
fix: bill cached and thinking tokens and carry refusal usage to the d…