design image generation broken: gpt-4o orchestrator + gpt-image-2 tool is an unsupported pairing (400)
- Dominant language
- TypeScript
- Stars
- 133k
- Forks
- 19.9k
- Avg merge
- 18h 46m
- Merged PRs (30d)
- 26
Description
> **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
```diff
# 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
```bash
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.
Contributor guide
Assessment
This issue has not been assessed yet.