Correction (updated): An earlier version of this issue claimed the Responses image_generation tool doesn't accept gpt-image-2 at all. That was wrong. The tool does accept gpt-image-2 — but only when the top-level orchestrator model is gpt-5. The actual bug is that gstack pairs gpt-image-2 with a gpt-4o orchestrator, which 400s. Details and both fixes below.
Summary
All design subcommands that generate images (/design-shotgun, variants, generate, iterate, evolve) fail with a generic 400 invalid_request_error from OpenAI. gstack calls the Responses API with a gpt-4o orchestrator and an image_generation tool set to model: "gpt-image-2". That combination is rejected: gpt-4o is too old to drive the gpt-image-2 tool. The same tool/model works under a gpt-5 orchestrator, and gpt-4o works fine with gpt-image-1.
This is a regression introduced in v1.43.2.0 (commit 66f3a180, 2026-05-21). Before that commit the tool call had no model field and worked via the default (gpt-image-1).
Affected version: 1.48.0.0 (present since 1.43.2.0)
Root cause
# design/src/variants.ts (commit 66f3a180) — top-level model is "gpt-4o"
- tools: [{ type: "image_generation", size, quality }],
+ tools: [{ type: "image_generation", model: "gpt-image-2", size, quality }],
The model field was bumped to gpt-image-2 while the orchestrator model stayed gpt-4o. gpt-4o + gpt-image-2 is an unsupported pairing and returns a generic 400.
Reproduction — the deciding variable is the orchestrator model
KEY=... # OpenAI key with image access
# FAILS — gstack's exact combo: gpt-4o orchestrator + gpt-image-2
curl -s https://api.openai.com/v1/responses \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"model":"gpt-4o","input":"a red square",
"tools":[{"type":"image_generation","model":"gpt-image-2","size":"1024x1024","quality":"low"}]}'
# -> HTTP 400 "There was an issue with your request. Please check your inputs and try again"
# WORKS — gpt-5 orchestrator + gpt-image-2
curl -s https://api.openai.com/v1/responses \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"model":"gpt-5","input":"a red square",
"tools":[{"type":"image_generation","model":"gpt-image-2","size":"1024x1024","quality":"low"}]}'
# -> HTTP 200, returns image_generation_call with a real base64 PNG
# WORKS — gpt-4o orchestrator + gpt-image-1 (or no model field, which defaults to gpt-image-1)
curl -s https://api.openai.com/v1/responses \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"model":"gpt-4o","input":"a red square",
"tools":[{"type":"image_generation","model":"gpt-image-1","size":"1024x1024","quality":"low"}]}'
# -> HTTP 200
| orchestrator |
image tool model |
result |
gpt-4o |
gpt-image-2 |
400 (gstack's current combo) |
gpt-5 |
gpt-image-2 |
200 |
gpt-4o |
gpt-image-1 |
200 |
gpt-4o |
(omitted → default) |
200 |
Confirmation that the gpt-5 path genuinely uses gpt-image-2 (not a silent downgrade): the two models validate sizes differently. gpt-image-2 rejects 512x512 with "below the current minimum pixel budget" and 999x999 with "must both be divisible by 16" (a continuous pixel-budget sizer), while gpt-image-1 rejects 512x512 with "Supported sizes are 1024x1024, 1024x1536, 1536x1024, and auto" (a fixed list). The gpt-5 path exhibits the gpt-image-2 sizing rules.
Why CI didn't catch it
The design tests (design/test/variants-retry-after.test.ts) inject a stubbed fetchFn returning canned successResponse() objects. No test sends a real request to OpenAI, so an unsupported orchestrator/model pairing passes CI green while the live feature is broken.
Fix — pick one
Option A (faithful — keep gpt-image-2): change the top-level orchestrator from gpt-4o to gpt-5 in the five call sites below. Requires gpt-5 access on the account.
Option B (widest compatibility — keep gpt-4o): change the image tool model back to gpt-image-1 (or drop the field, which defaults to it). Works on accounts without gpt-5 access.
Call sites:
design/src/variants.ts:73
design/src/generate.ts:50 (orchestrator) / :54 (image model)
design/src/iterate.ts:95,98 and :143,145
design/src/evolve.ts:65,67
Size note for gpt-image-2: dimensions must be divisible by 16 and above a minimum pixel budget. gstack's existing sizes (1024x1024, 1536x1024, 1024x1536) all qualify.
Optionally add one test that asserts on the outgoing request body (orchestrator + image model pairing), since the existing stubbed tests can't catch this class of bug.
Summary
All
designsubcommands that generate images (/design-shotgun,variants,generate,iterate,evolve) fail with a generic400 invalid_request_errorfrom OpenAI. gstack calls the Responses API with agpt-4oorchestrator and animage_generationtool set tomodel: "gpt-image-2". That combination is rejected:gpt-4ois too old to drive thegpt-image-2tool. The same tool/model works under agpt-5orchestrator, andgpt-4oworks fine withgpt-image-1.This is a regression introduced in
v1.43.2.0(commit66f3a180, 2026-05-21). Before that commit the tool call had nomodelfield and worked via the default (gpt-image-1).Affected version: 1.48.0.0 (present since 1.43.2.0)
Root cause
The
modelfield was bumped togpt-image-2while the orchestrator model stayedgpt-4o.gpt-4o+gpt-image-2is an unsupported pairing and returns a generic 400.Reproduction — the deciding variable is the orchestrator model
gpt-4ogpt-image-2gpt-5gpt-image-2gpt-4ogpt-image-1gpt-4oConfirmation that the
gpt-5path genuinely usesgpt-image-2(not a silent downgrade): the two models validate sizes differently.gpt-image-2rejects512x512with "below the current minimum pixel budget" and999x999with "must both be divisible by 16" (a continuous pixel-budget sizer), whilegpt-image-1rejects512x512with "Supported sizes are 1024x1024, 1024x1536, 1536x1024, and auto" (a fixed list). Thegpt-5path exhibits thegpt-image-2sizing rules.Why CI didn't catch it
The design tests (
design/test/variants-retry-after.test.ts) inject a stubbedfetchFnreturning cannedsuccessResponse()objects. No test sends a real request to OpenAI, so an unsupported orchestrator/model pairing passes CI green while the live feature is broken.Fix — pick one
Option A (faithful — keep gpt-image-2): change the top-level orchestrator from
gpt-4otogpt-5in the five call sites below. Requiresgpt-5access on the account.Option B (widest compatibility — keep gpt-4o): change the image tool
modelback togpt-image-1(or drop the field, which defaults to it). Works on accounts withoutgpt-5access.Call sites:
design/src/variants.ts:73design/src/generate.ts:50(orchestrator) /:54(image model)design/src/iterate.ts:95,98and:143,145design/src/evolve.ts:65,67Size note for
gpt-image-2: dimensions must be divisible by 16 and above a minimum pixel budget. gstack's existing sizes (1024x1024,1536x1024,1024x1536) all qualify.Optionally add one test that asserts on the outgoing request body (orchestrator + image model pairing), since the existing stubbed tests can't catch this class of bug.