"image_size must be a named preset" 400 on Sume: how to fix it
Sending image_size as a bare number or an empty object returns a 400 invalid_request. The three accepted shapes, a tested error table, and a safe builder.

If Sume's Image API answers with 400 invalid_request and the message "image_size must be a named preset, WIDTHxHEIGHT string, or {width,height} object.", you sent image_size as something else, most often a bare number such as 1024. Change it to one of the three accepted shapes: a named preset (landscape_16_9), a WIDTHxHEIGHT string ("1024x1536"), or an object with both width and height.
The error carries field: "image_size", so your client can point at the exact parameter. The cases below were run through the request normalizer on origin/main with openai/gpt-image-2.5, so the messages are the real ones.
The inputs that fail and the ones that pass
Number types are the usual trap, because a JSON number looks like a perfectly good size. Edge-only values (1024) are ambiguous: width, height or both? The API refuses to guess. An empty object fails with its own message, "image_size object requires width and height."
An object with both edges passes normalization, and GPT Image 2.5 gets quality: "high" added when you omit it, which is its documented default. Passing normalization is not the end of validation: the GPT 2.5 pixel rules (both edges multiples of 16, maximum edge 3840, aspect ratio at most 3:1, and between 655,360 and 8,294,400 pixels) still apply to the size (Sume Image API docs).
| image_size value | Result |
|---|---|
| 1024 (a number) | 400 invalid_request: must be a named preset, WIDTHxHEIGHT string, or {width,height} object |
| {} (empty object) | 400 invalid_request: image_size object requires width and height |
| "landscape_16_9" | accepted, passed through |
| "1024x1536" (string) | accepted |
| {"width": 1088, "height": 1360} | accepted, quality defaults to high |
A builder that cannot produce the error
Rather than hand-writing the field in every call site, build it in one function that validates the shape first. The version below checks the GPT 2.5 pixel rules locally, so you also catch a size the model would refuse before you spend a request. It is plain Python with no dependencies, and it prints a payload fragment you can merge into your request.
The rules in the function mirror the ones in the docs; if the catalog ever changes them, the catalog is the authority, not this snippet.
def gpt_image_size(width: int, height: int) -> dict:
"""Return an image_size object that satisfies the GPT Image 2.5 pixel rules."""
if width % 16 or height % 16:
raise ValueError("both edges must be multiples of 16")
if max(width, height) > 3840:
raise ValueError("maximum edge is 3840")
if max(width, height) / min(width, height) > 3:
raise ValueError("aspect ratio must be at most 3:1")
pixels = width * height
if not 655_360 <= pixels <= 8_294_400:
raise ValueError("total pixels must be 655,360 to 8,294,400")
return {"image_size": {"width": width, "height": height}}
print(gpt_image_size(1088, 1360))
print(gpt_image_size(2560, 1440))
try:
gpt_image_size(1000, 1000)
except ValueError as e:
print("rejected:", e)Related errors with the same cause
If you put pixels in size, the error is different: 400 unsupported_parameter, with a message that says explicit pixel sizes are not available on size and points to image_size or aspect_ratio. On models that only list ratios, a pixel string in either field is snapped to the nearest ratio rather than rejected; see what Sume sends for named presets.
For the full size rules on GPT Image 2.5, including the multiples-of-16 limit, see GPT Image 2.5 on Sume.
Related posts
More in Developers
- OS credential store vs sume login: where the key lives
Inngest v1.45.0 stores CLI OAuth credentials in the OS credential store. The Sume CLI stores its login key in ~/.sume-com/config.json; use env keys in CI.
- Instagram Reels API: a 100-posts-per-24-hours publish budget
The Instagram content publishing API limits an account to 100 API-published posts per moving 24 hours. A tested Python queue that spreads batch output under it.
- IPv6-only webhook endpoint: test Sume delivery before launch
OpenAI's API now accepts IPv6 connections. If your webhook host is IPv6-only, prove Sume can reach it with POST /v1/webhooks/test-deliveries first.
- Keep your Sora-style create_video() call: map it onto Sume
Sora's seconds, size and input_reference become duration, resolution plus aspect_ratio, and a first frame. Here is that map as a Python wrapper over Sume.
Written by Sume