Log requested vs stored model ids to find retired ids still in config
Sume runs a retired image id as its successor and stores the successor on the job. Compare the two ids after each submit to find stale config.

When a model is retired on Sume, a request that names it still succeeds, and the job stores the successor id. That makes the stored model on the job the cheapest drift detector you have: compare it with the id you sent, and log a warning when they differ. A retired id in your config then shows up in a log line the first day, instead of in a cost report next month.
Where the two ids are visible
The Image API docs say google/nano-banana-2 and nano-banana-2 run as Nano Banana 2.1 and that the job stores the 2.1 id. For sume/auto the stored model stays sume/auto, so a difference there is expected and should not warn. Bare legacy ids such as gpt-image-2 are accepted as aliases for their org-prefixed form, so a prefix-only difference is also expected.
| Requested | Stored on the job | Warn? |
|---|---|---|
| google/nano-banana-2 | google/nano-banana-2.1 | Yes: retired id in config |
| nano-banana-2 | google/nano-banana-2.1 | Yes: retired id in config |
| gpt-image-2 | openai/gpt-image-2 (org-prefixed form) | No: alias only |
| sume/auto | sume/auto | No |
Make the comparison strict enough
Strip the organization prefix before comparing, so the alias case stays quiet, and skip sume/auto. Anything else that differs is a real substitution. Keep the check in the code path that already reads the job, so it costs no extra request. If you submit with mode: "async", read the job once on completion and run the check there.
A warning is not an outage. The request worked, and the point is to update config on your schedule. Pin the successor id, redeploy, and the warning disappears.
The check
The helper takes the id you sent and the job envelope, and returns a message or None.
def bare(model_id: str) -> str:
return model_id.split("/")[-1]
def drift(requested: str, job: dict):
stored = job.get("model") or (job.get("job") or {}).get("model")
if not stored or requested == "sume/auto":
return None
if bare(requested) == bare(stored):
return None
return f"config asks {requested}, job ran {stored}: update the id"
print(drift("nano-banana-2", {"model": "google/nano-banana-2.1"}))
print(drift("gpt-image-2", {"model": "openai/gpt-image-2"}))
print(drift("sume/auto", {"model": "sume/auto"}))Pair it with a startup check
Drift detection after the fact works well with a startup check against GET /v1/images/models, which no longer lists retired ids. The startup check stops a deploy. The log check catches the old id that slipped through.
What to do with the warnings
Collect the warning lines for a week and sort them by requested id. Each distinct pair is one config line to change. Ship the change to the successor id, and the line stops appearing. Keep one test that feeds a retired id and expects a warning, so the check cannot silently rot.
Do not make the warning fatal in production. The docs describe retired ids as still working, and an outage caused by a log rule is worse than a stale id. Make it fatal in CI, where a pinned id that no longer matches the catalog should fail a build.
The same idea applies beyond images, but check the specific docs for each family before you assume a successor mapping. The image docs state the Nano Banana 2 rule directly. For video, the catalog is read from GET /v1/videos/models, and an unknown id is a model not found error, not a silent alias, so a startup check is the right tool there.
Sources
Related posts
More in Developers
- Log the Sume request_id in Python JSON logs, no keys or URLs
A small logging helper for failed /v1/videos calls: keep error.code, request_id and job id, and leave out the API key and signed media URLs.
- Longest AI video clip in one API call: max seconds per Sume model
In one Sume call, Seedance 2.5 and Wan 3.0 reach 30 seconds, Seedance 2.0, Kling v3 Pro and MiniMax reach 15, Gemini Omni Flash 1.1 stops at 10. Full table.
- MAI-Voice-2.1 SSML style="happiness" is not in the voice style list
Microsoft's MAI-Voice-2.1 SSML example uses style="happiness", but the Learn page's own style lists say happy or joyful. Check styles before you ship.
- mask_url edit on GPT Image 2.5: the mask is a guide, not a hard edge
OpenAI says GPT Image masking is prompt-based and may not follow the mask shape exactly. How that affects mask_url edits on Sume and a cheap way to test it.
Written by Sume