garrytan / garrytan/gstack

design image generation broken: gpt-4o orchestrator + gpt-image-2 tool is an unsupported pairing (400)

Open
#1,771 2 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.