Sume images 400: read details.supported and retry in Python

A 400 invalid_request from Sume's image API lists the accepted values in details.supported. Parse it in Python, then choose a value on purpose.

4 min readSume
All posts

When Sume's image API rejects a value the model does list as a field, it returns 400 invalid_request and puts the accepted values in error.details.supported (or the range in details.min and details.max). You can read that list in code and decide what to resend, instead of guessing from the model docs. When the model does not list the field at all, the code is unsupported_parameter instead, and there is no list to read.

The behavior below comes from running the request normalizer in Sume's repository on 2026-10-03; the rule that a parameter a model does not list is rejected rather than silently dropped is on the Image API page.

What does each 400 tell me?

Two different 400 codes are easy to confuse. unsupported_parameter says the field is not advertised by that model, and points at /v1/images/models through details.catalog_url. invalid_request says the field exists but your value is outside what the model accepts, and details.supported holds the allowed values.

Real rejections from the image request normalizer, run 2026-10-03. Model catalogs change, so read GET /v1/images/models for the current lists (docs.sume.com/models/images).
RequestCodeWhat the error carries
openai/gpt-image-2 with quality: "xhigh"invalid_requestsupported: low, medium, high
x-ai/grok-image with aspect_ratio: "4:5"invalid_requestsupported: 13 ratios, from 2:1 to 9:20
x-ai/grok-image with n: 2invalid_requestmin: 1, max: 1
recraft/recraft-v4 with output_format: "png"invalid_requestsupported: webp
google/nano-banana-2 with quality: "high"unsupported_parametercatalog_url: /v1/images/models
gpt-image-2.5-flare as the modelmodel_not_found (404)catalog_url: /v1/images/models

How do I handle it in Python?

Return the field and the list, and let the caller choose. Do not auto-pick the first entry: for quality that would quietly buy a cheaper image than you asked for, and for aspect_ratio it could change the crop. The function below only extracts the information; the sample body is the real shape for the xhigh row above.

def accepted_values(body):
    err = body.get("error") or {}
    details = err.get("details") or {}
    if err.get("code") != "invalid_request" or not isinstance(details, dict):
        return None
    if "supported" in details:
        return details.get("field"), list(details["supported"])
    if "min" in details and "max" in details:
        return details.get("field"), list(range(details["min"], details["max"] + 1))
    return None

sample = {"error": {"code": "invalid_request",
    "message": 'openai/gpt-image-2 does not accept quality "xhigh".',
    "details": {"field": "quality", "supported": ["low", "medium", "high"]}}}
print(accepted_values(sample))  # ('quality', ['low', 'medium', 'high'])

Should I retry a 400 automatically?

Only with a change you chose. A 400 is a validation failure, and the errors page lists validation as a category whose next action is to fix the input. Resending the same body repeats the same rejection, and the image page says failed generations are not billed.

A practical pattern is to check the catalog first: fetch GET /v1/images/models, read each model's supported_parameters, and validate your payload before you submit. Keep the 400 handler as a backstop for catalog changes, and log request_id from the error body so a rejected call can be traced.

Where do the lists come from?

The values in details.supported are the same descriptors the catalog publishes. The Image API page describes three kinds: enum (a discrete allowlist of strings), range (any integer between a minimum and maximum), and boolean (supported or absent). Because the error and the catalog are built from one source, a value you read from GET /v1/images/models is a value the 400 handler will accept.

That also means the error list can differ by model and over time. Do not copy a list from one model into another model's validation. Cache the catalog for the length of one batch run, and refetch at the start of the next.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume