10月の終わりに、8月に書いたこの記事を読み返していて、手が止まりました。
本文の冒頭は「あと2日」で始まっています。その2日はとうに過ぎていて、SDK の最新版も 2.18.1 から 2.33.0 まで進んでいました。当時の私は「手元で確認できるのは SDK の層まで」と書きましたが、その SDK の層の挙動そのものが、変わっているかもしれません。
そこで同じ確認を、バージョンを替えてやり直しました。結果から先にお伝えしますと、generate_images はいまも SDK に残っています。ところが 2.20.0 以降は、通信が始まる前に手元で止まるようになっていました。
SDK が告げている期限は、いまも2027年より前ではありません
まず、最新版に 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"))
# True2026年10月30日時点の最新版である 2.33.0 にも、generate_images はそのまま存在しています(8月15日時点の最新版は 2.18.1 でした)。「SDK を最新にしたから移行は済んだ」という考え方は、ここで崩れます。
メソッドにはデコレータで警告文が付いていました。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-images「次のメジャーリリースで削除される。ただし2027年1月1日より前ではない」。8月の時点の文面に、移行先の案内として URL が2本加わっていました。期限の書き方は変わっていません。
つまり SDK が管理している期限は、早くても2027年です。8月17日については、いまも一言も触れていません。
止まるのはメソッドではなく、モデルのほうです
整理すると、期限は1本ではなく複数あり、しかも決めている主体が違います。
| 何が終わるか | 期限 | 決めているもの | 手元で確認できるか |
|---|---|---|---|
generate_images メソッドの削除 |
次のメジャーリリース(2027年1月1日以降) | SDK のバージョン | できる |
| imagen-4.0 系3モデルの停止 | 8月17日(告知済みの期限) | サーバー側 | できない |
| Gemini 3 Image 系の停止 | 8月17日(告知済みの期限) | サーバー側 | できない |
個人開発で全部を一人で回していると、スクリプトが今日も動いたという事実が、そのまま点検の代わりになってしまいます。私が油断していたのは、まさにこの表の3列目と4列目でした。手元のスクリプトが今日も動くことは、モデルが明日も生きていることを一切保証しません。
止まるのはメソッドではありません。そのメソッドに渡している モデル ID のほうです。呼び出し箇所の洗い出しについては 8月17日の Gemini 画像生成モデル停止に備える に手順をまとめてありますので、まだ棚卸しをしていない方はそちらを先にご覧ください。
2.20.0 以降は、通信より前に手元で止まります
今回の読み返しで、いちばん見落としていたのがここでした。
同じ呼び出しを、バージョンを替えて走らせてみます。API キーはダミーの文字列です。
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])手元での結果は次のとおりです。
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 (同上)
2.33.0 ValueError (同上)2.19.0 までは、リクエストがサーバーまで届き、キーの検証で ClientError が返っていました。2.20.0 からは、クライアントの中で ValueError になり、通信は発生しません。途中の 2.21.0 から 2.24.0 も同じ ValueError でした。
ここで書いておきたいのは、確認できた範囲です。私が走らせたのはダミーのキーによる呼び出しで、Gemini Developer API モード(API キーで作ったクライアント)だけです。Gemini Enterprise Agent Platform モードで同じ呼び出しが通るかどうかは、試していません。ですので「2.20.0 以降は画像生成ができない」とまでは言えません。言えるのは、API キーで作った Developer API 向けのクライアントでは、この呼び出しが手元で弾かれる という一点です。
8月に私が書いた「手元で確認できるのは SDK の層まで」は、半分だけ当たっていました。SDK の層は、確認できるだけでなく、バージョンを上げた途端に答えが変わる層でもあったのです。
警告は1プロセスに1回だけで、設定では取り戻せません
もうひとつ、8月に確かめたことを 2.33.0 でも確かめました。
この非推奨警告は、同じプロセスの中で1回しか出ません。しかも warnings の設定を強めても、2回目は出ませんでした。
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}")2.18.1 では次のとおりでした。
call#1: warnings=1 err=ClientError
call#2: warnings=0 err=ClientError2.33.0 でも警告の件数は同じで、1回目が1件、2回目が0件です。違うのは err の欄だけで、こちらは先ほどの表のとおり ValueError に変わります。
simplefilter("always") を指定しているのに、2回目はゼロ件でした。SDK 側が独自のフラグで「一度出したら以降は出さない」と決めているため、利用者側のフィルタ設定では取り戻せません。
警告の種類も確認しておきます。
from google.genai import _common
print([c.__name__ for c in _common.ExperimentalWarning.__mro__])
# ['ExperimentalWarning', 'Warning', 'Exception', 'BaseException', 'object']DeprecationWarning ではなく、Warning の直下に置かれた独自クラスでした。非推奨の検出を DeprecationWarning で見張っている仕組みを持っている場合、この警告はその網に掛かりません。
常駐しているワーカーや、朝に起動して夜まで回り続けるバッチでは、起動直後の1回を見逃すとその日はもう二度と出ません。見逃したくない場合は、起動時に一度だけ拾ってログへ流しておくのが確実です。
import logging
import warnings
logging.captureWarnings(True)
warnings.simplefilter("always")logging.captureWarnings(True) を入れておくと、警告が py.warnings ロガー経由で流れます。標準エラー出力を誰も見ていない運用でも、ログ基盤には残ります。
API に届く前と後で、エラーの層が分かれます
移行作業中に出るエラーは、見た目が似ていても発生している層が違います。手元で実際に踏んだものを並べておきます。
1. API キーを渡していない場合
ValueError: No API key was provided. Please pass a valid API key.クライアントを作る時点で止まります。通信は発生していません。
2. 引数の置き場所を間違えた場合
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, ...]これも通信前です。aspect_ratio は GenerateContentConfig の直下ではなく、ImageConfig の側に置きます。2.33.0 の ImageConfig が受け取るのは aspect_ratio image_size person_generation prominent_people output_mime_type output_compression_quality image_output_options の7つでした。引数の移し先の全体像は generate_images から generate_content へ書き換えるとき、引数は素直に移りません に対応表があります。
3. Developer API モードで generate_images を呼んだ場合(2.20.0 以降)
ValueError: This method is only supported in Gemini Enterprise Agent Platform
mode, not in Gemini Developer API mode.今回新しく分かった層です。通信前に、クライアントが自分で止めます。
4. キーが無効だった場合
ClientError: 400 INVALID_ARGUMENT.
{'error': {'code': 400, 'message': 'API key not valid. ...',
'status': 'INVALID_ARGUMENT'}}ここで初めてサーバーからの応答になります。ClientError が返ってきたということは、リクエスト自体は届いているという意味です。
5. モデルが停止した後
8月17日を過ぎたいまも、この層は私の手元で再現できていません。有効なキーで停止対象のモデル ID を呼ぶ検証をしていないため、停止後の応答の形は書けません。推測で例を作るより、書けないとお伝えするほうが誠実だと考えています。層としては4番と同じ、サーバーからの応答側で起きるはずです。
見分け方はこう覚えておくと迷いません。ValueError と ValidationError は手元のコードとクライアントの側の問題で、ClientError から先は向こう側の状態の問題です。画像生成まわりのエラーをもう少し広く見ておきたい方は Gemini 画像生成でつまずく5つのエラー も参考になるかと思います。
期限を過ぎたいま、確認しておきたい3つのこと
優先順に3つだけ挙げます。
- モデル ID を渡している箇所を数えてください。
generate_imagesを検索するのではなく、imagen-4.0という文字列を検索してください。メソッド名は残りますが、告知されていた停止はモデル ID に掛かっていました。 - SDK を上げる前に、
ValueErrorで止まる経路を洗い出してください。 2.20.0 以降は Developer API モードのgenerate_imagesが手元で弾かれます。固定していたバージョンを上げた日に、画像生成だけが落ちる、という事態を避けられます。 - 警告を捨てない設定にしておいてください。
logging.captureWarnings(True)の2行を入れるだけです。今回の件に限らず、次の非推奨に気づくのが数週間早くなります。
8月の私は、SDK が静かだったことを「まだ大丈夫」の材料にしかけていました。10月の私は、その SDK の側も数バージョンのあいだに挙動を変えていたことを、読み返してようやく知りました。
確認した日付とバージョンは、確認結果と一緒に書き残しておきます。 期限の話は、この線引きを守るだけで、読み返したときの手触りがずいぶん変わるのです。
まずは手元のロックファイルで、google-genai が 2.19.0 以前に留まっていないかを見てみていただければ幸いです。