At the end of October I reread this article, the one I wrote in August, and stopped.
The opening line says "two days left." Those two days are long gone, and the SDK has moved from 2.18.1 to 2.33.0. Back then I wrote that the only thing I could verify locally was the SDK layer. It hadn't occurred to me that the SDK layer itself might have changed underneath me.
So I ran the same checks again, across versions. The short version: generate_images is still in the SDK. But from 2.20.0 onward, it fails on your own machine before anything goes over the network.
The deadline the SDK tells you about is still 2027
First question: does the latest release still have generate_images?
pip index versions google-genai
# google-genai (2.33.0)
# Available versions: 2.33.0, 2.32.0, 2.31.0, ...from google.genai import models
print(hasattr(models.Models, "generate_images"))
# TrueVersion 2.33.0 is the newest release as of October 30, 2026 (it was 2.18.1 on August 15), and the method is still right there. So "I upgraded the SDK, so I must have migrated" falls apart immediately.
The method carries a deprecation notice on a decorator. This is the full text from 2.33.0:
The generate_images method is deprecated and will be removed in the next
major release (not before Jan. 1 2027). Please use the generate_content
method with image models instead. See
https://ai.google.dev/gemini-api/docs/deprecations#imagen-models and
https://docs.cloud.google.com/gemini-enterprise-agent-platform/models/capabilities/image-generation#generate-imagesRemoved in the next major release, and not before January 1, 2027. Compared with August, the notice gained two links pointing at migration guidance; the deadline wording is unchanged.
So the deadline the SDK owns is, at the earliest, two months away. It says nothing about August 17.
What shuts down is the model, not the method
Laid out side by side, there is more than one deadline, and different parties control them.
| What ends | When | Who controls it | Verifiable locally? |
|---|---|---|---|
Removal of generate_images |
Next major release (not before Jan 1, 2027) | Your SDK version | Yes |
| Shutdown of the three imagen-4.0 models | August 17 (as announced) | Server side | No |
| Shutdown of the Gemini 3 Image models | August 17 (as announced) | Server side | No |
Working as an indie developer, with nobody else running these scripts, "it ran today" quietly becomes my entire verification step. Columns three and four are where I had been fooling myself. A script that runs clean today tells you nothing about whether the model is alive tomorrow.
The thing that stops is not the method. It is the model ID you hand to that method. If you haven't inventoried your call sites yet, Getting Ready for the August 17 Gemini Image Model Shutdown walks through that first.
From 2.20.0, it stops locally, before the network
This is the part I had missed entirely.
Here is the same call, run against several versions. The API key is a dummy string.
from google import genai
client = genai.Client(api_key="DUMMY")
try:
client.models.generate_images(
model="imagen-4.0-generate-001",
prompt="a quiet morning street",
)
except Exception as e:
print(type(e).__name__, str(e)[:100])What I got:
2.18.1 ClientError 400 INVALID_ARGUMENT ... API key not valid.
2.19.0 ClientError 400 INVALID_ARGUMENT ... API key not valid.
2.20.0 ValueError This method is only supported in Gemini Enterprise
Agent Platform mode, not in Gemini Developer API mode.
2.25.0 ValueError (same)
2.33.0 ValueError (same)Through 2.19.0, the request reached the server and came back as a ClientError from key validation. From 2.20.0 it becomes a ValueError inside the client, and nothing is sent. I also tried 2.21.0 through 2.24.0, and they behave the same way.
Let me be precise about what this shows. I ran a dummy key against a Gemini Developer API client, and nothing else. I did not test whether the same call works in Gemini Enterprise Agent Platform mode, so I can't tell you that image generation is gone as of 2.20.0. What I can say is narrower: a client built from an API key rejects this call on your machine.
My August line, "all you can verify locally is the SDK layer," turned out to be half right. The SDK layer is verifiable, but it is also a layer whose answer changes the day you bump the version.
The warning fires once per process, and you can't get it back
One more thing from August, rechecked on 2.33.0.
That deprecation warning appears exactly once per process. Turning the warning filters up to maximum does not bring it back.
import warnings
from google import genai
client = genai.Client(api_key="YOUR_API_KEY")
for n in (1, 2):
with warnings.catch_warnings(record=True) as caught:
warnings.simplefilter("always")
try:
client.models.generate_images(
model="imagen-4.0-generate-001",
prompt="a quiet morning street",
)
except Exception as e:
err = type(e).__name__
print(f"call#{n}: warnings={len(caught)} err={err}")On 2.18.1:
call#1: warnings=1 err=ClientError
call#2: warnings=0 err=ClientErrorOn 2.33.0 the warning counts are identical, one then zero. Only the err column changes, to the ValueError from the table above.
Zero on the second call, with simplefilter("always") in effect. The SDK keeps its own flag that says "emitted once, never again," and no filter setting on your side overrides it.
The warning category is worth a look too:
from google.genai import _common
print([c.__name__ for c in _common.ExperimentalWarning.__mro__])
# ['ExperimentalWarning', 'Warning', 'Exception', 'BaseException', 'object']It sits directly under Warning, not under DeprecationWarning. If you have tooling that watches for DeprecationWarning to catch exactly this class of problem, this notice slips right past it.
For a long-running worker, or a batch job that starts in the morning and runs all day, missing that one line at startup means you will not see it again that day. If you want to keep it, catch it at startup and push it into your logs:
import logging
import warnings
logging.captureWarnings(True)
warnings.simplefilter("always")logging.captureWarnings(True) routes warnings through the py.warnings logger. Even when nobody is watching stderr, the message lands somewhere durable.
Errors before the network and errors after it are different problems
While migrating, you will hit failures that look alike but come from very different layers. These are the ones I actually ran into.
1. No API key
ValueError: No API key was provided. Please pass a valid API key.This stops at client construction. Nothing left your machine.
2. An argument in the wrong place
from google.genai import types
types.GenerateContentConfig(aspect_ratio="9:16")pydantic_core._pydantic_core.ValidationError: 1 validation error for
GenerateContentConfig
aspect_ratio
Extra inputs are not permitted [type=extra_forbidden, ...]Also pre-network. aspect_ratio doesn't live on GenerateContentConfig; it belongs to ImageConfig. In 2.33.0, ImageConfig accepts seven fields: aspect_ratio, image_size, person_generation, prominent_people, output_mime_type, output_compression_quality, and image_output_options. For the full mapping of where every old argument lands, see Rewriting generate_images as generate_content, where the arguments actually go.
3. generate_images on a Developer API client (2.20.0 and later)
ValueError: This method is only supported in Gemini Enterprise Agent Platform
mode, not in Gemini Developer API mode.The new one. The client stops you before anything is sent.
4. An invalid key
ClientError: 400 INVALID_ARGUMENT.
{'error': {'code': 400, 'message': 'API key not valid. ...',
'status': 'INVALID_ARGUMENT'}}Now you are looking at a server response. A ClientError means the request reached the API.
5. A retired model
Even with August 17 behind us, I haven't reproduced this layer. I did not call the retired model IDs with a working key, so I can't show you what the response looks like, and I would rather say so than invent a sample. Structurally it should belong with case four: a server-side response.
A rule of thumb that keeps these straight: ValueError and ValidationError are about your code and your client, while anything from ClientError onward is about the state on the other end. For a wider tour of image generation failures, Five Errors You'll Hit with Gemini Image Generation covers more ground.
Three things worth checking now that the date has passed
In priority order:
- Count your model IDs, not your method calls. Grep for the string
imagen-4.0, not forgenerate_images. The method stays; the announced shutdown was attached to the model. - Find the
ValueErrorpaths before you bump the SDK. From 2.20.0,generate_imageson a Developer API client is rejected locally. Better to learn that from a grep than from the morning your pinned version moves and only image generation falls over. - Stop throwing warnings away. Two lines of
logging.captureWarnings(True)setup. It won't just help here — it buys you weeks of lead time on the next deprecation.
In August I treated the SDK's silence as evidence that I was fine. In October I found that the SDK itself had changed its answer a few versions later, and I only noticed because I reread my own article.
Write down the date and the version next to every result you record. That one habit changes how a deadline note reads when you come back to it.
A good first step: open your lockfile and see whether google-genai is still sitting at 2.19.0 or earlier.