GEMINI LABJP
SHUTDOWN — gemini-robotics-er-1.6-preview retires today, August 31. Any code still pointing at that preview model stops working from here onDEPRECATION — September 30 is the next date to watch: the gemini-omni-flash-preview endpoint goes away and needs swapping for gemini-omni-1.1-flash, which reached GA on August 27VIDEO — The Omni 1.1 Flash GA adds video extension through the extend task, and interpolation by passing two images to image_to_video so you can fix the first and last frame up frontVIDEO — A resolution parameter in video_config now accepts 360p, 720p as the default, 1080p, and 4k, with the note that 1080p and 4K outputs are produced by upscalingSPEECH — gemini-3.5-transcribe reached GA on August 26 with utterance-level language detection across 85+ languages, speaker diarization, word-level timestamps, and up to 1,000 custom vocabulary termsSPEECH — gemini-3.5-transcribe-live streams both ways over WebSockets on the Live API, with interim and finalized transcription events, a Smart transcription mode, and several VAD settingsSHUTDOWN — gemini-robotics-er-1.6-preview retires today, August 31. Any code still pointing at that preview model stops working from here onDEPRECATION — September 30 is the next date to watch: the gemini-omni-flash-preview endpoint goes away and needs swapping for gemini-omni-1.1-flash, which reached GA on August 27VIDEO — The Omni 1.1 Flash GA adds video extension through the extend task, and interpolation by passing two images to image_to_video so you can fix the first and last frame up frontVIDEO — A resolution parameter in video_config now accepts 360p, 720p as the default, 1080p, and 4k, with the note that 1080p and 4K outputs are produced by upscalingSPEECH — gemini-3.5-transcribe reached GA on August 26 with utterance-level language detection across 85+ languages, speaker diarization, word-level timestamps, and up to 1,000 custom vocabulary termsSPEECH — gemini-3.5-transcribe-live streams both ways over WebSockets on the Live API, with interim and finalized transcription events, a Smart transcription mode, and several VAD settings
Articles/Dev Tools
Dev Tools/2026-08-30Advanced

Why Shipped Clients Deserve a Refusal, Not a Silent Model Substitution

A model can retire, but the apps already on people's phones cannot. This is how I built a sunset ledger keyed on output contracts, and how I now back-date my own deadline from the version residue curve.

Gemini API227model deprecation2indie development20release engineeringHTTP

Premium Article

The crash report pointed at a fifteen-line function that turns a category name into a screen label. Not the network layer. Not the response decoder. The very last hop before rendering.

The cause was nowhere near that function. Our gateway had been quietly rewriting a retired model ID to its successor, and the successor had grown two extra values in its category enum.

Rewriting felt like the kind thing to do. Better to keep serving traffic than to hand a 410 to an app someone already installed. And it did keep serving traffic — that is exactly why nobody noticed.

"Mostly working" is the hardest state to detect

The shipped client recognized six categories. The successor returned eight. The two new ones show up in only a slice of real traffic. Here is the distribution, reproduced locally.

import json, random
 
V12 = {"nature","abstract","city","animal","art","minimal"}   # what the shipped app knows
V20 = list(V12) + ["japanese","texture"]                       # what the successor returns
 
def client_v12_parse(body):
    obj  = json.loads(body)                                    # layer 1: transport + JSON
    text = obj["candidates"][0]["content"]["parts"][0]["text"]
    rec  = json.loads(text)                                    # layer 2: structured output
    if rec["category"] not in V12:                             # layer 3: enum -> view model
        raise ValueError("unknown category: %s" % rec["category"])
    return rec["category"]
 
def make_response(category):
    inner = json.dumps({"category": category, "confidence": 0.9})
    return json.dumps({"candidates":[{"content":{"parts":[{"text": inner}]}}]})
 
random.seed(20260830)
sample = [random.choices(V20, weights=[22,18,14,12,10,10,9,5])[0] for _ in range(1000)]
 
ok = enum_err = 0
for c in sample:
    try:
        client_v12_parse(make_response(c)); ok += 1
    except ValueError:
        enum_err += 1
print(ok, enum_err)      # -> 849 151

849 of 1,000 succeed. Roughly 15% fail.

A total outage would have been easier to handle. At 15%, users experience it as "sometimes it just doesn't categorize." On my side, suspicion falls on whatever shipped most recently. What actually changed was a server-side rewrite rule, and not one line of app code had moved.

The model ID never appears where the exception does

The second problem is where the failure surfaces. Drop the same code and look at the frames.

import traceback, sys
try:
    client_v12_parse(make_response("japanese"))
except Exception:
    for i, f in enumerate(traceback.extract_tb(sys.exc_info()[2])):
        print("frame%d: %s() line %d" % (i, f.name, f.lineno))
# frame0: <module>()          line 24
# frame1: client_v12_parse()  line 12

In a real app there is a view-model builder in between, so the reported frame sits even closer to the UI. Along every path, the model ID you sent is absent from the stack.

Automated crash clustering does not rescue you here. The stack trace, as a string, carries no trace of the fact that a retired model was still being requested. When the cause sits on the API side, the reported location is always somewhere far away.

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 decide when a successor model may be swapped in silently based on the output contract rather than the model lineage, so you never inherit a failure whose cause is invisible after the sunset date
You will be able to back-date your own shipping deadline from a published sunset date, accounting for how slowly updates actually reach installed apps
You will be able to explain why silent substitution stays hidden, using a measurement where 849 of 1,000 responses pass through unharmed
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

Dev Tools2026-08-24
Gemini quietly drops %1$s from translations, and no reviewer catches it
Format specifiers go missing, turn full-width, or get duplicated when Gemini translates app strings. Here are the four failure modes I keep seeing in production, how to stop them at generation time, and a short check that catches the rest.
Dev Tools2026-08-22
The One Call I Refuse to Hand Gemini During a Phased Release
Day one of a phased release has nowhere near the sample size to tell a healthy build from a broken one. Here is the three-state rollout gate I use, and the narrow job I give Gemini inside it.
Dev Tools2026-08-17
Your Shipped App Still Remembers the Retired Model
Finishing the server-side migration is only half of a model retirement. The older builds of your app still hold the old model name, and once the cutoff passes, rolling back stops being a recovery option. Here is how I moved model resolution onto the server.
📚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 →