Image retry returns 409 idempotency_conflict: new key per payload
A 409 idempotency_conflict on a Sume image job means the same Idempotency-Key was reused with a different payload. Derive the key from the payload in Python.

A 409 idempotency_conflict on a Sume image job means you reused an Idempotency-Key for a request that is not the same operation and payload. The generation admission page defines it exactly that way: the same key was reused for a different operation or payload, and the client should reuse keys only for exact retries. If you changed quality, the prompt, or a reference image and kept the old key, you will see this error instead of a new image.
The fix is not to retry harder. It is to give each distinct request its own key, and to give an actual retry (same body, after a timeout) the key it already had. Sume's Jobs and results page says a retried submit with the same key returns the original job instead of billing a second one.
When is the same key correct, and when is it a conflict?
Think of the key as the name of one intended image. Two calls that mean the same image should share it; two calls that mean different images must not.
| Situation | Key | Result |
|---|---|---|
| Client timed out; resend the identical body | Same key | The original job comes back; no second charge |
Submit got 429 queue_full or provider_capacity_exceeded | Same key | Retry later with the same key |
You raised quality from medium to high and resubmit | New key | A new job; reusing the old key returns 409 idempotency_conflict |
| Same key sent to a different endpoint or model | New key | 409 idempotency_conflict |
How do I derive a key that follows the payload?
Hash the canonical JSON of the request, and add a version prefix you can bump to force a fresh run on purpose. Identical payloads then map to one key, and any change to the body (including quality) produces another.
import hashlib
import json
def idem_key(payload, version="v1"):
body = json.dumps(payload, sort_keys=True, separators=(",", ":"))
return version + "-" + hashlib.sha256(body.encode()).hexdigest()[:32]
a = {"model": "openai/gpt-image-2.5", "prompt": "red mug", "quality": "medium"}
b = {**a, "quality": "high"}
print(idem_key(a) == idem_key(a)) # True
print(idem_key(a) == idem_key(b)) # FalseWhat if I want the same image again on purpose?
Bump the version prefix. That is a new intent, so it gets a new key and a new, billed job. Remember that Sume's image API does not accept seed, so a second run of the same prompt is not guaranteed to match the first; a key replay is the only way to get the original result back.
Check the request_id in the 409 body before you debug further, and log it with your own key. Do not include API keys or signed URLs when you share logs.
What should my retry code do on each status?
Treat 409 idempotency_conflict as a bug in your key logic, not a transient fault: do not loop on it. Log the key and the payload hash, fix the derivation, and resubmit with a key that matches the new body. For 429 and 503 capacity errors, the guidance is the opposite: retry later with the same key.
A related 409 family exists for jobs, such as job_not_cancelable and job_generation_already_started; those say the job is past the point where the operation is valid, and they are unrelated to key reuse.
Sources
Related posts
More in Developers
- Image-to-image strength or denoise: no field on Sume, do this
No strength, denoise or seed field exists on Sume's Image API; it returns 400 unsupported_parameter. How to control how far an edit moves from the reference.
- 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.
- Image API provider.only returns 400 provider_not_available on Sume
Sume's Image API accepts provider routing fields but publishes one sume endpoint per model, so any other provider slug returns 400 provider_not_available.
- Inngest 1.45 returns 400 for unknown v2 fields: treat a Sume 400 alike
Inngest v1.45.0 rejects unmapped REST v2 request fields with HTTP 400. A Sume 400 invalid_request is the same fix-the-request signal; do not retry it.
Written by Sume