Kimi K3 is now availableExplore Kimi K3
Gemini 3.6 Flash API migration gateway separating explicit request errors from a silent ignored parameter
Tutorial

Gemini 3.6 Flash Migration: Five API Changes and One Silent Failure

Jacey
Jacey
Founder
July 21, 2026
20 min read
TL;DR Migrating to gemini-3.6-flash or gemini-3.5-flash-lite involves five request changes. Four of them return HTTP 400, so you find out immediately. One of them does not: temperature, top_p and top_k are now accepted and ignored. If your pipeline relies on temperature=0 for stable output, it will keep returning 200 OK while the guarantee you were counting on is gone. Fix that one first, then the four loud ones.
Last verified: 2026-07-21
Google shipped Gemini 3.6 Flash and Gemini 3.5 Flash-Lite on 21 July 2026. Most launch coverage is about benchmarks and price. This page is about something narrower and more urgent: the request format changed, and Google has said the new rules apply to these two models and every model released after them.

If you are swapping a model ID in a config file and expecting the rest to keep working, read the first section before you deploy.

The five changes, ranked by how you find out

ChangeWhat happens on the new modelsHow you find out
temperature, top_p, top_kAccepted, then ignoredNothing. No error, no warning.
thinking_budget sent together with thinking_levelRequest rejectedHTTP 400
Last turn in the request has role modelRequest rejectedHTTP 400
FunctionResponse without call_id and nameRequest rejectedHTTP 400
candidate_countNot supported in Gemini 3.xRequest fails or the field is dropped

Four of these five failures announce themselves. Your integration tests catch them, your error tracker pages you, you fix them in an afternoon. The first one is the one that reaches production.

The dangerous one: temperature, top_p and top_k are now ignored

Google's own wording is unambiguous: these parameters "are deprecated and ignored," and "in future model generations, supplying these parameters returns an HTTP 400 error." The instruction is to remove them from all requests.

Read that sequence carefully, because the order matters to you. Today the parameter is a no-op. Later it becomes an error. That means the period where you are most likely to be wrong about your own system is right now, while everything still returns 200.

Gemini 3.6 Flash sampling parameters appear active but their signals disappear before the production inference path
Gemini 3.6 Flash sampling parameters appear active but their signals disappear before the production inference path
Sampling controls can still be accepted by the request path while having no effect on Gemini 3.6 Flash output.

Which pipelines break without an error

A silent no-op is only dangerous if you were depending on the parameter. Four common setups were:

  • Determinism pipelines. Anything that sets temperature=0 to make repeated calls agree with each other: cache keys built from model output, deduplication passes, classification jobs that feed a downstream state machine. The setting is now inert, so whatever output stability it was buying you is no longer being bought.
  • Golden-file and snapshot tests. Suites that pinned temperature=0 and diff the model's output against a stored expected string. These start flaking after the model swap, and the flake looks like a model quality regression rather than a config problem, which sends you debugging in the wrong direction.
  • Structured output held together by low temperature. Teams that never adopted structured outputs and instead kept temperature near zero plus top_p tight so the model would reliably emit parseable JSON. Both knobs are now inert at once.
  • Tuned per-route configs. Products that expose a creativity slider, or route "summarize" at one temperature and "brainstorm" at another. The slider still moves in your UI. It no longer moves anything in the model.

None of these produce a stack trace. They produce output that is slightly different from what you validated, in a system that reports itself healthy.

Your gateway will not warn you either

This is the part that catches even careful teams. Model gateways publish machine-readable metadata describing which parameters each model supports, and tooling reads that metadata to decide what to send.

As of 21 July 2026, OpenRouter's models endpoint still lists temperature, top_p and seed in supported_parameters for both google/gemini-3.6-flash and google/gemini-3.5-flash-lite. The gateway accepts those fields and forwards them. The model on the other end ignores them. Nothing in that chain raises an error, and nothing in the metadata tells you the field is dead.
Google's own surfaces have the same lag. The enterprise platform page for Gemini 3.6 Flash still displays default values for temperature, topP and topK (1.0, 0.95 and 64) on the same page that states custom values will be ignored.
The practical consequence is blunt: anyone tuning temperature today to improve output quality on these models is tuning a no-op. If your team has a ticket open for "find the right temperature for the summarizer," close it.

What replaces temperature

Google's stated replacement is not another parameter. It is the system instruction: write the behavior you want as a rule the model reads, rather than as a sampling constant.

That is a real change in how you express intent, so translate rather than delete:

What you used to encode as a numberWhere it goes now
temperature=0 for terse, repeatable answersA system instruction that states the required format, length and tone, plus a rule to answer with no preamble
Low temperature to keep JSON parseableStructured outputs, which gemini-3.6-flash and gemini-3.5-flash-lite both support
High temperature for varietyAn instruction asking for N distinct options in one response, since candidate_count is also gone
The third row is worth pausing on. Deleting temperature and candidate_count in the same migration removes both of the mechanisms teams used for output variety. If a feature of yours depended on variety, it needs an actual redesign, not a config edit.

How to find every call site before you deploy

Search your codebase for the parameter names rather than trusting the config layer, because these values are usually set in several places by different people:

# Gemini-native and OpenAI-compatible spellings, plus the config objects that carry them
grep -rn "temperature\|top_p\|topP\|top_k\|topK\|candidate_count\|candidateCount" \
  --include="*.py" --include="*.ts" --include="*.js" --include="*.go" --include="*.java" .

# The wrappers that hide them
grep -rn "generation_config\|generationConfig\|GenerateContentConfig\|thinking_budget\|thinkingBudget" .

Check the results outside application code too: YAML and JSON config, prompt-management tools, notebooks, eval harnesses, and any Terraform or admin console that stores model settings. A knob set in a dashboard six months ago is exactly the kind of thing that survives a code review.

The four that fail loudly

These are simpler, because the API tells you. Fix them in whatever order your test suite surfaces them.

thinking_budget and thinking_level cannot both be present

Gemini 3.x replaced the numeric thinking_budget with the string enum thinking_level, which takes minimal, low, medium or high. Sending both in one request returns 400. Google's migration note is to replace thinking_budget with thinking_level, not to keep both for compatibility.

Two defaults worth knowing while you pick a value, because they differ between the two models:

  • gemini-3.6-flash defaults to medium.
  • gemini-3.5-flash-lite defaults to minimal, which is tuned for throughput.
Google states plainly that the minimal default on Flash-Lite is not suitable for use as an autonomous sub-agent, and that on multi-step tasks it will terminate tool calls prematurely. If Flash-Lite is going to write code, run terminal commands or call external APIs for you, raise it to medium or high deliberately. This is the one migration edit where accepting the default is an actual product decision rather than a formality.
That warning reproduces, and it is worth knowing what the failure looks like, because it does not look like a failure. We ran 216 calls across eight model and thinking-level configurations on launch day, nine tasks repeated three times each. Exactly one produced a wrong answer: Flash-Lite at its minimal default, on a three-step notification chain, failing all three attempts. The shape was identical each time. It called the first two tools correctly, then stopped and reported success without sending the final notification. No error, no exception, a well-formed response that a downstream service would accept. Raising the same model to high passed the task every time.
The migration lesson is narrow but sharp. If you are moving a multi-step workflow onto Flash-Lite and you leave thinking_level unset, the request will not fail. It will return a confident answer about work it did not finish. Set the level explicitly, then assert on the effects your workflow was supposed to produce rather than on the response you got back.

You can no longer prefill a model turn

If the last non-empty turn in your request has the role model, the API returns 400. Prefilling was a common trick: you would append a partial assistant turn like {"role": "model", "parts": [{"text": "{"}]} to force the model to open with a JSON brace, or to suppress a chatty preamble.

Both of those goals move into the same two places as everything else: a system instruction that states the rule, or structured outputs when you need a machine-parseable shape. Search your code for any request builder that appends a final assistant or model message, especially retry and continuation logic, which is where prefills tend to be generated dynamically rather than written literally.

Every FunctionResponse needs call_id and name

When you use the generateContent API, each FunctionResponse must carry both the matching call_id and the name of the function. Hand-rolled tool loops are the usual casualty here, because plenty of them were written when a bare result was enough and they reconstruct the response object from scratch instead of echoing back what the model sent.
The fix is mechanical: keep the call_id from the model's function call, and put it back on the response you return. If you built your tool loop on a framework, update the framework rather than patching around it.

candidate_count is gone

candidate_count is not supported in Gemini 3.x. Remove it. If you were using it to sample several answers and pick the best, that logic now has to be explicit: either ask for multiple options inside one response, or issue multiple requests and pay for them separately.

Before and after: a request that migrates cleanly

Here is a Gemini-native call carrying every deprecated field, and the version that survives the move.

# BEFORE: works on 2.5-era models, breaks or silently misbehaves on 3.6 Flash
config = {
    "temperature": 0,          # now ignored, no error
    "top_p": 0.95,             # now ignored, no error
    "top_k": 40,               # now ignored, no error
    "candidate_count": 1,      # unsupported in Gemini 3.x
    "thinking_budget": 8192,   # 400 if it meets thinking_level
}

# AFTER: intent moved from sampling constants into instructions
config = {
    "system_instruction": (
        "Answer in at most three sentences. Use plain declarative statements. "
        "Do not add a preamble, restate the question, or offer follow-ups. "
        "If the answer is uncertain, say so in one sentence."
    ),
    "thinking_level": "medium",
}
The point of the "after" block is not that it is shorter. It is that the behavior you want is now written down in words the model actually reads, which also means the next engineer can see what you intended. A temperature=0 in a config file never explained itself.
If you reach these models through an OpenAI-compatible gateway, the same deletions apply, because the gateway forwards the fields and the model discards them. On EvoLink that call is the standard OpenAI SDK with the base URL swapped:
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["EVOLINK_API_KEY"],
    base_url="https://api.evolink.ai/v1"
)

response = client.chat.completions.create(
    model="gemini-3.6-flash",
    messages=[
        {"role": "system", "content": "Answer in at most three sentences. No preamble."},
        {"role": "user", "content": "Summarize this incident report."}
    ]
    # no temperature, no top_p: they would be accepted and ignored downstream
)

print(response.choices[0].message.content)
import OpenAI from "openai";

const client = new OpenAI({
  apiKey: process.env["EVOLINK_API_KEY"],
  baseURL: "https://api.evolink.ai/v1",
});

const response = await client.chat.completions.create({
  model: "gemini-3.6-flash",
  messages: [
    { role: "system", content: "Answer in at most three sentences. No preamble." },
    { role: "user", content: "Summarize this incident report." },
  ],
  // no temperature, no top_p
});

console.log(response.choices[0].message.content);
One detail that saves a round of confusion: the model ID is exactly gemini-3.6-flash. There is no preview suffix and no date stamp, so there is no dated alias to pin. If your deployment process assumes a -preview or -001 variant exists, that assumption fails at request time.
This page only covers the fields that changed. For the full request reference, the capability matrix and the error messages you are likely to hit on a first call, see our Gemini 3.6 Flash guide.

A migration order that catches the silent failure

The sequence matters, because the loud errors are easy and the quiet one is not. Do it in this order:

Gemini 3.6 Flash production migration workflow from request inventory through validation, canary rollout and rollback
Gemini 3.6 Flash production migration workflow from request inventory through validation, canary rollout and rollback
A safe Gemini 3.6 Flash rollout inventories hidden controls first, validates behavior, then canaries production traffic with a rollback path.
  1. Inventory first. Run the greps above and list every place a sampling parameter is set, including config stores and dashboards. Write down which behavior each one was protecting.
  2. Translate intent, do not just delete. For every temperature you find, decide what it was for and write the equivalent system instruction. Deleting without translating is how you ship a quality regression.
  3. Fix the 400s. Swap thinking_budget for thinking_level, remove candidate_count, remove prefilled model turns, add call_id and name to every FunctionResponse.
  4. Choose a thinking level on purpose, especially on Flash-Lite, where the minimal default is unsuitable for autonomous multi-step work. This is also the largest cost lever in the migration: on our task set, 3.6 Flash at minimal cost 73.6% less per pass than the same model at the medium default, and thinking tokens accounted for 85% of billed output at medium. Whether your workload survives the drop is the thing to test, not whether the saving is real.
  5. Re-baseline your snapshot tests against the new model before you compare anything. Old golden files were produced under a parameter that no longer applies, so they are not a valid reference point.
  6. Run your evals on both models over the same task set and compare output distributions, not just pass rates. Silent behavior changes show up as drift in format, length and verbosity before they show up as wrong answers.
  7. Canary on real traffic and watch downstream parsers, not just the API error rate. If something is going to break quietly, it breaks in the code that consumes the model's output, not in the call itself.
Step 5 is the one teams skip. If you diff new output against golden files generated when temperature=0 still did something, every diff looks like a model problem and none of them are.

Let Google's migration skill do the first pass

Google publishes an agent skill for this migration that you install once and point at your project.
npx skills add google-gemini/gemini-skills --skill gemini-interactions-api --global

Then, in a coding agent, point it at your project:

/gemini-interactions-api migrate my app to Gemini 3.6 Flash

It is worth running. It handles the mechanical work: finding deprecated fields, rewriting request construction, updating call sites, which covers most of step 3 above.

What it cannot do is step 2. A tool can see that temperature=0 should be removed. It cannot know that the value was there because a downstream service assumed identical output on identical input, and it cannot write the system instruction that preserves that intent. Treat the skill as a code-sweeping pass, then do the intent translation yourself.

Retirement schedule: when the choice stops being yours

Migration is optional right up until it is not. Google's deprecation page lists the dates:
ModelShutdown dateRecommended replacement
gemini-2.5-flash16 October 2026gemini-3.6-flash
gemini-2.5-flash-lite16 October 2026gemini-3.1-flash-lite
gemini-3.1-flash-lite7 May 2027gemini-3.5-flash-lite
gemini-3-flash-previewNo shutdown date announcedgemini-3.6-flash
gemini-3.6-flash, gemini-3.5-flash-liteNo shutdown date announcedNot applicable
Note the second row, because it is the easiest thing on this page to get wrong. The replacement Google names for gemini-2.5-flash-lite is gemini-3.1-flash-lite, not the newly released gemini-3.5-flash-lite. Jumping straight to the newest Lite model is a defensible choice, but it is your choice, not the documented upgrade path, and it is a two-generation jump rather than one. Plan and test it as such.
Two dates are doing real work here. If you are on either 2.5 Flash model, you have until 16 October 2026, which is roughly three months from this article's publication. If you are on gemini-3-flash-preview, there is no announced end date, but preview models are not something to build a roadmap on.

Computer Use: four official pages, two answers

One capability question cannot be settled from documentation right now. Whether these models support Computer Use is stated inconsistently across Google's own material:

Four official pages, two contradictory answers, no way to resolve it by reading. If Computer Use is on your critical path, probe it on your own account and endpoint before you commit, and keep a fallback model wired up. This section will be updated with a tested answer and the date it was observed. Every other change in this guide is documented consistently; this one is not.

What this means if you are re-picking a provider this week

A migration you did not schedule has landed on your sprint, and the work is a day or two of careful editing rather than a weekend rewrite. Since you are already touching every call site, this is a natural moment to look at how the model reaches you at all.

Two things are worth checking while you are in there:

  • Can you run the old and new models side by side during the cutover? Step 6 above requires it. If your setup makes running gemini-3.5-flash and gemini-3.6-flash against the same task set awkward, that friction will be there for the next migration too, and there will be a next one: Google has said these rules apply to every model released from here on.
  • How fast does a new model become callable for you? gemini-3.6-flash reached general availability with no preview suffix on day one. The gap between a model shipping and your code being able to call it is a cost you pay on every launch.
EvoLink is built around both of those. One OpenAI-compatible endpoint reaches Gemini, Claude, GPT and the rest, so an A/B between two models is a change to the model string rather than a second SDK and a second set of credentials, and new models are available through the same endpoint you already use. If you want to see the current status of this specific model first, our Gemini 3.6 Flash release tracker has availability and model ID details, and the 3.6 Flash versus 3.5 Flash comparison covers whether the upgrade is worth doing at all, which is a different question from how to do it safely.
If this is not your first Gemini migration this year, two earlier guides cover their own model pairs: moving from Gemini 3 Flash Preview to Gemini 3.5 Flash on the Flash line, and the Gemini 3 Pro deprecation guide on the Pro line. Read them for the pair they name, not for this one. The parameter deprecations on this page begin with the 3.6 generation, so a guide written for an earlier pair will tell you that sampling parameters still work, and on gemini-3.6-flash they no longer do.

FAQ

Does Gemini 3.6 Flash return an error if I send temperature? No. Today temperature, top_p and top_k are accepted and ignored, with no error and no warning. Google has stated that future model generations will return HTTP 400 for these parameters, so the silence is temporary, but for now a request carrying them looks completely healthy.
What replaces temperature=0 for deterministic output? Google's documented replacement is the system instruction: state the required format, length and tone as rules the model reads. For machine-parseable output, use structured outputs, which both new models support. There is no numeric parameter that takes temperature's place.
Can I still use thinking_budget with gemini-3.6-flash? No. Gemini 3.x uses the string enum thinking_level with values minimal, low, medium and high. Sending thinking_budget and thinking_level in the same request returns HTTP 400. The default is medium on 3.6 Flash and minimal on 3.5 Flash-Lite.
What is the official replacement for gemini-2.5-flash-lite? Google's deprecation page names gemini-3.1-flash-lite, not gemini-3.5-flash-lite, and gives a shutdown date of 16 October 2026. You can move to 3.5 Flash-Lite instead, but that is a two-generation jump and your own decision rather than the documented path.
Do these changes apply to Gemini 3.5 Flash-Lite too? Yes. The deprecated sampling parameters, the thinking_level switch, the prefill restriction, the FunctionResponse requirements and the removal of candidate_count all apply to gemini-3.5-flash-lite as well, and Google has said they apply to every model released after these two. The code changes are the same either way, so you can start the migration before you have settled which of the two you are moving to. That choice is a separate question, covered in our Gemini 3.6 Flash versus 3.5 Flash-Lite comparison.
Is there a dated or preview version of the model ID I should pin? No. The model ID is gemini-3.6-flash, with no preview suffix and no date stamp. If your deployment tooling expects a dated alias, it will fail at request time.

Sources

Ready to Reduce Your AI Costs by 89%?

Start using EvoLink today and experience the power of intelligent API routing.