GEMINI LABJP
MODEL — Gemini 3.5 Flash reaches GA and now powers gemini-flash-latestAGENT — Managed Agents enter public preview in the Gemini API, running in isolated Google-hosted Linux sandboxesSEARCH — File Search adds multimodal search, embedding and searching images natively via gemini-embedding-2WEBHOOK — Event-driven webhooks arrive for the Batch API and long-running operations, replacing pollingEMBED — gemini-embedding-2 is now generally available for production embeddingsDEPRECATION — Several image generation models shut down on August 17, so plan migrations nowMODEL — Gemini 3.5 Flash reaches GA and now powers gemini-flash-latestAGENT — Managed Agents enter public preview in the Gemini API, running in isolated Google-hosted Linux sandboxesSEARCH — File Search adds multimodal search, embedding and searching images natively via gemini-embedding-2WEBHOOK — Event-driven webhooks arrive for the Batch API and long-running operations, replacing pollingEMBED — gemini-embedding-2 is now generally available for production embeddingsDEPRECATION — Several image generation models shut down on August 17, so plan migrations now
Articles/Updates
Updates/2026-07-04Intermediate

Before the August 17 Gemini Image Model Shutdown: Inventory Where You Actually Call Them First

Some Gemini image generation models retire on August 17. Before choosing a replacement, here is how to inventory which models are actually being called, and from where, using your request logs.

Gemini API167image generation2model migration2deprecation6operations8

When I saw the notice that some image generation models would retire on August 17, the first thing I did was not to pick a replacement. What made me stop was a simpler, more uncomfortable fact: I couldn't say for certain which of my own scripts were calling which model, or when.

I run a few pipelines that generate images for wallpaper apps as an indie developer, and model IDs end up scattered in more places than you'd expect — a validation script from months ago, a batch that only runs at month-end, a string buried in a config file. Even if I settle on one GA model to migrate to, missing a single call site means the thing that breaks on the morning of August 17 is the one job I never noticed. So before migrating, I did an inventory. Here's the process.

Why grep alone misses call sites — three blind spots

The obvious first move is to search the whole repository for the model name. That's useful, but incomplete. Relying on static string search alone leaves three gaps.

First, model IDs loaded from environment variables, config files, or a database. The code only says os.environ["IMAGE_MODEL"], and the actual value lives only in the deployment environment. Second, IDs passed in as arguments. If you've built a wrapper around the API, the model name may come from the caller, and static analysis can't tell you which value actually arrives. Third, old jobs you assume are already dead. A schedule you thought you disabled quietly still running is the scariest pattern in any deprecation.

In short, static code search tells you where a model might be called, but not whether it's actually being called right now. Collecting those two things separately is the point of this article.

Aggregate the models that are actually being called from your logs

Request logs fill the gap that grep leaves. If you record the model ID and a timestamp on every API call, you can mechanically compute which models were called, how recently, and how often. Even if you don't log yet, if your calls pass through a single wrapper, one added line starts the record today.

Here's a minimal wrapper that records each call before running it.

import json, time, pathlib
 
LOG_PATH = pathlib.Path("logs/model_calls.jsonl")
LOG_PATH.parent.mkdir(parents=True, exist_ok=True)
 
def call_image_model(client, model_id: str, prompt: str, *, caller: str):
    """Wrapper for image generation. Records model_id and caller before running."""
    record = {
        "ts": time.time(),
        "model": model_id,
        "caller": caller,  # e.g. an identifier for the call site: "wallpaper_batch.generate"
    }
    with LOG_PATH.open("a", encoding="utf-8") as f:
        f.write(json.dumps(record, ensure_ascii=False) + "\n")
 
    return client.models.generate_images(model=model_id, prompt=prompt)

Always passing caller is the key. Later you can trace not just "which model is used most" but "which process is calling that model," all in one pass.

Then aggregate the accumulated logs. Group the retiring model IDs and report each one's call count, last-called date, and callers.

import json, pathlib
from collections import defaultdict
from datetime import datetime, timezone
 
# List the model IDs retiring on August 17 (check the official deprecation list and update).
RETIRING = {
    "gemini-3.1-flash-image-preview",
    "gemini-3-pro-image-preview",
}
 
stats = defaultdict(lambda: {"count": 0, "last_ts": 0.0, "callers": set()})
 
for line in pathlib.Path("logs/model_calls.jsonl").read_text(encoding="utf-8").splitlines():
    rec = json.loads(line)
    if rec["model"] not in RETIRING:
        continue
    s = stats[rec["model"]]
    s["count"] += 1
    s["last_ts"] = max(s["last_ts"], rec["ts"])
    s["callers"].add(rec.get("caller", "unknown"))
 
for model, s in sorted(stats.items(), key=lambda kv: kv[1]["count"], reverse=True):
    last = datetime.fromtimestamp(s["last_ts"], tz=timezone.utc).strftime("%Y-%m-%d")
    callers = ", ".join(sorted(s["callers"]))
    print(f"{model}: {s['count']} calls / last {last} / callers: {callers}")

Run this and, for each retiring model, you see at a glance whether it's still alive, how frequently, and who calls it. A count of zero means the migration is less urgent even if the code still exists. Conversely, a caller you overlooked in grep may show up here by name for the first time. In my case, a validation batch I thought I'd disabled surfaced with a last call three days prior — a quiet moment of dread.

Assign a migration priority to each call site you found

Once the inventory is in, don't try to migrate everything at once — assign priorities. The three inputs are call volume, recency, and whether it runs unattended. Unattended jobs especially deserve a higher priority even at low volume, because when they stop, no one notices right away.

Nature of the call siteMigration priorityReason
Unattended scheduled batch, called recentlyHighestA stoppage goes unnoticed and its impact spreads quietly
User-triggered with high call volumeHighA shutdown directly degrades the experience
Manually run validation or experiment scriptsMediumLittle real harm if it stops, but neglect breeds confusion later
Zero calls in the logsLow (but consider deleting)Effectively unused — a good chance to remove it from the code

Replace the highest-priority sites with your chosen GA model first, then run the same log aggregation again. If calls to the retiring models no longer appear in the newer records, that path's migration is done. Not skipping this "confirm in the logs after switching" step is, I've found, the surest way to pass August 17 quietly.

For choosing the replacement model and the code diffs to verify during the switch, I've written up Gemini's image generation preview models retire on June 25 — the code diffs and verification steps for moving to GA. For the pipeline-side preparation that keeps the morning of a shutdown calm, What I learned on the morning a preview image model stopped — Gemini image model GA migration and a deprecation-resilient pipeline is a useful companion.

Keep model IDs in one place

The biggest lesson from this inventory was that the more model IDs are written directly throughout the code, the more searching each deprecation forces on you. To prepare for the next one, consolidate model IDs into a constants module or configuration and have call sites reference them by name — so next time, one change is enough. The thinking behind pinning model IDs and detecting changes, including the accident of a default model silently moving up, is explored in Don't let "the default model just went up" become an incident in the Gemini API — pinning model IDs and detecting default changes.

As a concrete first step you can take today, add one line of caller-tagged logging to your image generation calls. By August 17, where your code truly needs migration will be visible as data, not guesswork. Thank you for reading.

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 $10 for lifetime access
View Membership →

If you found this article helpful, a small tip ($1.50) would mean a lot to us. Your support helps keep this site ad-free and covers server and hosting costs.

Related Articles

Updates2026-06-12
Gemini Lab This Week: An Outage, Two Migration Deadlines, and Four Posts to Read Before June 25
Editor's notes on four posts for a turbulent week: surviving the Gemini outage, migrating off the preview image models before June 25, fixing the outputs schema removal, and structuring App Store rejection replies.
Updates2026-05-06
Gemini API Developer Update for May 2026 — What Changed and What You Should Do
A developer-focused roundup of Gemini API changes in May 2026. Covers Gemini 3.2 impressions, the June Gemini 2.0 Flash deprecation deadline, and what to prepare before Google I/O 2026.
Updates2026-05-05
Two Weeks Until Google I/O 2026: What Gemini API Developers Should Prepare Right Now
With Google I/O 2026 just around the corner, here's what developers running Gemini API in production should do this week — from pinning model versions and recording baselines to tracking deprecation timelines before the announcements hit.
📚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 →