Pin the image model id on the queue row so a swap can't break old jobs

Store the Sume model id on each queued render row at enqueue time, then re-point only rows still carrying a retired id. Python sqlite3 sample for gpt-image-1.

5 min readSume
All posts

Write the model id into the job row when you enqueue it, and have the worker read it from the row, not from current config. That way a deploy that changes your default model never changes what an in-flight job asks for. It also gives you one query that finds every queued row still holding a retired id once OpenAI's gpt-image-1 shutdown on October 23, 2026 gets close.

Without the column, a worker reads today's config for yesterday's job. That is fine until you change the config mid-batch and half the batch renders on each model.

Schema and the remap query

The table needs a model column that is not null. The remap is a single update that touches only queued rows whose id is in a retired set, so rows that already succeeded keep the id they were rendered with.

import sqlite3

RETIRED = ("openai/gpt-image-1", "gpt-image-1", "gpt-image-1-mini", "gpt-image-1.5")
NEW = "openai/gpt-image-2.5-sunburst"

db = sqlite3.connect("jobs.db")
db.execute("create table if not exists render_jobs("
           "id integer primary key, prompt text, model text not null, "
           "status text default 'queued')")

def enqueue(prompt, model=NEW):
    cur = db.execute("insert into render_jobs(prompt, model) values (?, ?)",
                     (prompt, model))
    db.commit()
    return cur.lastrowid

def remap_queued():
    marks = ",".join("?" * len(RETIRED))
    cur = db.execute(f"update render_jobs set model = ? where status = 'queued' "
                     f"and model in ({marks})", (NEW, *RETIRED))
    db.commit()
    return cur.rowcount

if __name__ == "__main__":
    enqueue("mug on linen", "gpt-image-1")
    print("re-pointed", remap_queued())

Which ids count as retired?

On Sume the matching ids are openai/gpt-image-2.5-sunburst and openai/gpt-image-2.5. Sume does not list any gpt-image-1 id, so an unknown id returns 404 model_not_found rather than quietly routing somewhere else.

Retire dates from the vendor page, read 2026-10-06
Retired idShutdown dateVendor-listed replacement
gpt-image-12026-10-23gpt-image-2.5-sunburst or gpt-image-2.5-flare
gpt-image-1-mini2026-12-01gpt-image-2.5-sunburst or gpt-image-2.5-flare
gpt-image-1.52026-12-01gpt-image-2.5-sunburst or gpt-image-2.5-flare
chatgpt-image-latest2026-12-01gpt-image-2.5-sunburst or gpt-image-2.5-flare

Keep the idempotency key in the row too

Store the Idempotency-Key next to the model. A retry with the same key and payload returns the original job with idempotency_hit: true. After a remap the payload changes, so mint a new key for the re-pointed row; reusing the old one returns 409 idempotency_conflict.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume