◉GEMINI LABJP
●FLASH — 3.7 Flash and 3.5 Flash are deprecated. Requests to the old names are routed to 3.8 / 3.6 Flash automatically●NANO 2.1 — gemini-nano-banana-2.1 is GA. gemini-3.1-flash-image is deprecated with no shutdown date yet●DEADLINE — veo-3.1 previews and gemini-omni-flash-preview shut down Oct 22; the old Deep Research agent follows Oct 23 (11-12 days left)●Q&A — Users report Gemini CLI returns a 400 error when you pass more than 128 tools●TTS 3.8 — Gemini 3.8 Flash TTS and Flash-Lite TTS are GA, with a new Voices endpoint●NEW — Keep money and health talk off your history: check temporary chat and settings●FLASH — 3.7 Flash and 3.5 Flash are deprecated. Requests to the old names are routed to 3.8 / 3.6 Flash automatically●NANO 2.1 — gemini-nano-banana-2.1 is GA. gemini-3.1-flash-image is deprecated with no shutdown date yet●DEADLINE — veo-3.1 previews and gemini-omni-flash-preview shut down Oct 22; the old Deep Research agent follows Oct 23 (11-12 days left)●Q&A — Users report Gemini CLI returns a 400 error when you pass more than 128 tools●TTS 3.8 — Gemini 3.8 Flash TTS and Flash-Lite TTS are GA, with a new Voices endpoint●NEW — Keep money and health talk off your history: check temporary chat and settings
Articles/API / SDK
◈ API / SDK/2026-08-27Intermediate

Record what you send before you try to measure whether temperature still works

Deprecated sampling parameters still return 200 and are silently ignored. Here is how a runtime recorder caught the call sites grep and AST both missed, kept the construction site attached to each config, and turned the ledger into a CI gate.

Gemini API247temperature4deprecation9static analysisCI7indie development28

✦ Premium Article

I read the one-line changelog entry, grepped my own code, and found three hits. temperature, top_p and top_k had been deprecated.

Three felt manageable. I nearly moved on.

What changed my mind was looking at the requests that were actually going out. There were five.

The awkward part of this kind of change is that it never surfaces as a failure. A request carrying a deprecated parameter still comes back 200. The value is accepted and then ignored. Code that believes it pinned temperature to zero keeps running, pinning nothing. No exception, no log line.

As an indie developer running a handful of small pipelines, I once catalogued how my toolchain reacts to a configuration key that does not exist. The answers fell into three tiers. The TypeScript compiler and ESLint fail outright. wrangler prints a warning and continues. npm and vitest say nothing at all. The tier that has always cost me the most hours is the third one.

Gemini's sampling deprecation sits squarely in that third tier.

Measuring "does it still work" is the wrong tool for an audit

The developer forums have been circling the same question: how do you inventory this, given there is no runtime signal?

The obvious answer is to send one prompt many times at temperature 0 and again at temperature 1, and check that the spread of outputs does not change. As a way of convincing yourself, that works fine.

As an audit tool, it does not. The classification jobs I run barely move even at temperature 1. When the answer space is closed, raising the value changes nothing regardless of deprecation. In that regime, "the spread did not change" is evidence for neither conclusion. There is a whole class of jobs where the test cannot decide anything.

And even a successful measurement tells you one thing about one job. That is not what a migration needs. A migration needs a complete list of where you are sending what.

So I reversed the order. Measuring effect went to the back of the queue. Recording what gets sent went to the front.

The three call sites grep found

To test this properly I set up five jobs that build their config in five different ways — roughly the spread you find in a codebase that has grown for a while.

# app/jobs/a_direct.py — typed config, keyword arguments
from google.genai import types
 
def build():
    return types.GenerateContentConfig(temperature=0.2, top_k=40)
# app/jobs/b_dict_literal.py — dict literal
def build():
    return {"temperature": 0.9, "response_mime_type": "application/json"}
# app/jobs/c_assigned.py — assigned after the fact
def build(t: float):
    cfg = {"max_output_tokens": 512}
    cfg["temperature"] = t
    return cfg
# app/jobs/d_profile.py — loaded from an external JSON profile
from app.common.config import load_profile
 
def build():
    return load_profile("caption")   # caption.json holds {"temperature": 0.9, "top_p": 0.95}
# app/jobs/e_merged.py — merged through a shared helper
from app.common.config import merged
 
def build():
    return merged("extract", candidate_count=1)   # extract.json holds {"temperature": 0.0}

Now grep:

$ grep -rn --include='*.py' 'temperature\|top_p\|top_k' app | wc -l
3

Jobs d and e never appear, because the string does not exist in any Python file.

Widening the search to JSON produces five hits. But the two extra lines are the profile definitions themselves, and they tell you nothing about which job reads them. Three jobs sharing one profile still look like a single line. So does a profile nobody reads anymore. It is not usable as a count of call sites.

✦

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
✦You will be able to prove on your own codebase why a setting that looks like 3 call sites under grep is actually being sent from 5
✦You will be able to close the audit gap around configs that arrive from external profiles or shared helpers, before a migration quietly leaves some behind
✦You will be able to show that a deprecation cleanup is finished as a CI pass rather than as something someone remembers doing
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 $15 for lifetime access
View Membership →

Related Articles

◈ API / SDK2026-09-29
The Size Column Said 'F6' and 'About A4' — I Let Gemini Read It, and Let a Table Do the Math
An artist's spreadsheet mixed 'F6', '41×31.8cm', and 'about A4' in one size column. Here is the small tool I built: Gemini reads each cell, a lookup table converts to centimeters, and the artwork image decides the orientation. Working code, step by step.
◈ API / SDK2026-09-11
When Transcription Keeps Mangling Proper Nouns: Choosing What Earns a Custom Vocabulary Slot
gemini-3.5-transcribe accepts up to 1,000 custom_vocabulary entries, but filling the list is not the goal. Here is a 60-line script that picks entries from your own reference-and-hypothesis pairs, plus the rules I use to decide what to leave out.
◈ API / SDK2026-09-08
Writing my first Gemini cost estimate in two columns, one for now and one for January
Introductory pricing for Gemini Flash ends on December 31, 2026, and standard pricing starts on January 1, 2027. Staying on an older generation does not avoid it. Here is the small, working estimator I use to see both prices at once.
📚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