FLUX 3 Image 503: read the JSON status before you retry
BFL says a FLUX 3 Image 503 may be retryable once you check the JSON status; 422, 400 and 402 are not. Sume sync failures return a 502 with a retryable flag.

A 503 from the FLUX 3 Image endpoint is not automatically a retry. BFL's generate docs say a 503 may be retryable only after you check the status in the JSON body, and they list other errors that a retry will never fix: 422 for unknown fields, 400 for an oversized image and 402 for insufficient credits. Read the body first, then decide. FLUX 3 Image is not in the Sume image catalog today; check GET /v1/images/models for the live list. The catalog lists FLUX.2 Pro and FLUX.2 Flex.
What BFL documents
The table lists what the BFL page says about errors and job statuses. It gives no numeric concurrency limit, so do not hard-code one.
| Signal | Meaning on the BFL page | Resubmit? |
|---|---|---|
| 422 | Unknown fields in the request | No, fix the body |
| 400 | Image too large | No, shrink the image |
| 402 | Insufficient credits | No, add credits |
| 503 | Check the JSON status first | Maybe, after reading the status |
| Pending / Reasoning / Generating | Job still running at the polling_url | No, keep polling |
| Ready | Result in result.sample; signed URLs expire within 1 hour | No, download now |
| Request Moderated / Content Moderated / Error | Terminal states | Not unchanged; the same input is likely to fail again |
Why a blind retry costs you
The last row is advice, not a BFL statement: BFL lists the moderation statuses as terminal outcomes, so a blind retry of the same prompt has little reason to succeed.
- Polling a Pending or Generating job is safe; submitting the same prompt again starts a second job.
- A 402 retried in a loop only repeats the failure.
- Result links expire within 1 hour, so copy images to your own storage early.
How Sume job errors differ
Sume shapes failures differently. A synchronous call to POST /v1/images waits up to 30 seconds. If the job fails terminally inside that wait, you get a 502 with an error envelope that carries code, message, retryable and next_action. If the wait budget runs out, or you send mode: "async", you get a 202 job envelope and read the images from GET /v1/jobs/{id}/result. Branch on the status code, not on the body shape. Per the Sume docs, failed or cancelled generations are not billed.
| Status | What it means | What to do |
|---|---|---|
| 200 | Image response with data[].url and usage.cost | Use the URL |
| 202 | Job envelope (slow job or async mode) | Poll status_url, read result_url |
| 502 | Terminal failure inside the wait, error envelope | Check retryable and next_action |
A retry loop that reads the flag
This loop retries only when Sume marks the failure retryable. It uses a FLUX.2 Pro id from the Sume catalog, because FLUX 3 Image is not listed.
import os, time, requests
H = {"Authorization": "Bearer " + os.environ["SUME_API_KEY"]}
def generate(prompt):
for attempt in range(3):
r = requests.post("https://api.sume.com/v1/images", headers=H, timeout=60,
json={"model": "black-forest-labs/flux.2-pro", "prompt": prompt})
if r.status_code == 200:
return r.json()["data"][0]["url"]
if r.status_code == 202:
return "slow job, poll " + r.json()["data"]["status_url"]
err = r.json().get("error", {})
print(attempt, err.get("code"), err.get("retryable"), err.get("next_action"))
if not err.get("retryable"):
raise RuntimeError(err.get("message"))
time.sleep(2 ** attempt)
raise RuntimeError("still failing after 3 tries")
print(generate("a ceramic mug on a wooden table, soft window light"))Sources
Related posts
More in Developers
- FLUX 3 Image 0-1000 boxes to pixels on a 1920x1080 canvas
FLUX 3 Image boxes are [top, left, bottom, right] on a 0-1000 grid. The BFL example [250, 50, 850, 650] becomes x 96, y 270, 1152x648 pixels on 1920x1080.
- Forgot the TTS language field? Sume only infers Korean and Japanese
Omit language on a Sume TTS request and the voice check assumes English. Sume infers ko or ja only when Hangul or kana outnumber Latin letters.
- 404 format_run_wrong_path: read a Sume run by its own id
A 404 on GET /v1/formats/{handle}/{slug}/runs/{run_id} is a wrong URL, not a lost run. The did_you_mean hint names GET /v1/format-runs/{run_id}.
- Run stuck queued? queue.state waiting vs runtime_unavailable
queue.state waiting is normal pickup; runtime_unavailable means nothing claimed the run. Position is always null. Back off, then contact support.
Written by Sume