DEV Community

ushiro
ushiro

Posted on

A Model Google Lists as Shut Down Answered Me Today. Read `modelVersion` Before You Trust It.

Google's Gemini deprecation page defines its terms up front:

Once a model is "shutdown", it is completely turned off, and the endpoint is no longer
available.

The same page marks already-shutdown models with a grey row, and gemini-3.1-flash-lite-preview
is grey. Shut down. Endpoint gone.

I called it on 2026-09-20:

curl -s "https://generativelanguage.googleapis.com/v1beta/models/\
gemini-3.1-flash-lite-preview:generateContent?key=$KEY" \
  -H "Content-Type: application/json" \
  -d '{"contents":[{"parts":[{"text":"What is 7 times 6? Answer with the number only."}]}]}'
Enter fullscreen mode Exit fullscreen mode
HTTP 200
"42"
Enter fullscreen mode Exit fullscreen mode

No error, no warning header, no notice in the payload.

One field says what actually happened

{
  "candidates": [ ... ],
  "modelVersion": "gemini-3.1-flash-lite",
  "usageMetadata": { "totalTokenCount": 16, "serviceTier": "standard" }
}
Enter fullscreen mode Exit fullscreen mode

I asked for gemini-3.1-flash-lite-preview. I was served gemini-3.1-flash-lite — the GA model
named in the replacement column of the very row that says the preview is shut down.

Calling the GA name directly confirms they are the same thing now:

request = gemini-3.1-flash-lite          -> modelVersion = gemini-3.1-flash-lite
request = gemini-3.1-flash-lite-preview  -> modelVersion = gemini-3.1-flash-lite
Enter fullscreen mode Exit fullscreen mode

The retired ID resolves to its successor. Your call succeeds. A different model answers it.

Before you generalise this — two things that are NOT the story

I went looking for "vendor ignores its own shutdown dates" and did not find it. Two corrections
I had to make to my own reasoning, both from reading the page more carefully:

The dates in that table are not shutdown dates. The page says so explicitly:

The shutdown dates listed in the table indicate the earliest possible dates on which a model
might be retired. We will communicate the exact shutdown date to users with advance notice.

So a model still running past the date in its row is not a broken promise. It is the documented
behaviour. Two other previews — gemini-3.1-flash-image-preview and gemini-3-pro-image-preview
— are past their June 25 dates and still live, and their rows are not grey. Google is not
claiming they are shut down. Nothing is wrong there.

The scope is small. Of the 32 rows the page marks as already shut down, exactly two still
appear in the live ListModels output:

gemini-3.1-flash-lite-preview   -> gemini-3.1-flash-lite   (generation verified)
gemini-2.5-pro-preview-tts      -> countTokens returns 200 (generation not tested)
Enter fullscreen mode Exit fullscreen mode

Thirty of thirty-two are genuinely gone. This is a narrow gap, not a pattern of neglect.

Why the narrow version still matters

An alias is the kind choice. The alternative is a hard failure on the shutdown date, which takes
down every service still pointing at the old name — including the ones whose owners never read
the deprecation page. Google kept those callers running and pointed them at the model it had
already told everyone to migrate to. If your code is "call an LLM, get text back," this saved
you an outage and cost you nothing.

But nobody types -preview into a config file by accident. You pin a specific model ID for one
reason: you want the same model next month that you had this month.

That is the property the alias silently removes. Your request still succeeds, your tests still
pass, your error rate stays flat — and the weights answering are not the weights you evaluated
against. Prompts tuned on that preview, a golden-output suite, a published benchmark, a cached
embedding space, a customer-facing behaviour you signed off on: all measured against a model
that the vendor says is turned off.

The failure mode is not an outage. It is quiet drift behind a green dashboard.

Nobody has said how long this lasts

Here is the part I want to be clearest about, because it is the part that should change what you
do.

The aliasing is not documented anywhere I can find. The deprecation page does not mention
aliases, redirects, or fallbacks — the words do not appear on it. It says the opposite: that a
shut-down model's endpoint is no longer available. There is no stated policy for how long a
retired ID keeps resolving, no commitment that it will keep working tomorrow, and no announcement
channel for the day it stops.

Which means you cannot plan against it. The behaviour I measured today is not a feature you were
offered and it is not a guarantee you can hold anyone to. It is an undocumented grace period of
unknown length, and the day it ends, the failure will look exactly like the outage the alias was
preventing — except now it arrives with no date attached, because the date already passed months
ago and you stopped watching.

Treat it as time to migrate, not as a migration you can skip.

What to actually do

Log modelVersion on every call. One field, and the only thing in the response that tells
you what answered. If you store nothing else about a request, store this.

Assert on it where it matters. A suite that exists to prove your prompt still behaves should
fail when the model underneath changes, not when the output finally drifts far enough for a human
to notice:

const res = await model.generateContent(req);
if (res.modelVersion !== EXPECTED_MODEL) {
  throw new Error(`served by ${res.modelVersion}, pinned ${EXPECTED_MODEL}`);
}
Enter fullscreen mode Exit fullscreen mode

Read a retirement row as "the answer may change", not "the call may fail". Those are
different events, and only one of them pages you.

Most LLM plumbing I see checks the status code and reads candidates[0]. Everything between
those two is treated as noise. Here the entire signal was in the noise.


Verified against the live pages and API on 2026-09-20. I keep a record of these dates and what
they said before they changed:
aichangewatch.com/deprecations

Top comments (0)