Seedance and Kling submit errors: which to retry and which to fix
A Sume video submit can fail with 402, 429 queue_full, 429 rate_limited or 400. Which to retry with the same key and which need a changed request.

Retry 429 rate_limited and 429 queue_full with backoff and the same Idempotency-Key. Fix 402 insufficient_credits by adding balance first, and fix any 400 or 404 by changing the request, since resending the same body gets the same answer. That is the whole decision tree for a Seedance or Kling submit on Sume.
The details matter because the three look alike in logs. The rules below come from Sume's errors page and generation admission docs.
Which submit errors are worth retrying?
429 queue_full means your processing slots and the waiting queue are both full. Poll existing jobs, wait until one finishes, and retry. 429 rate_limited is request-volume protection and also clears with backoff. In both cases, reuse the same Idempotency-Key: if the first attempt actually created a job, you get that job back, not a second paid one.
A 5xx or a network timeout is ambiguous, because the job may have been created. Retry with the same key for the same reason.
Which errors need a different request?
402 insufficient_credits fires before any provider work, when Sume cannot reserve the estimated cost. Retrying without topping up fails again. A 400 validation error names the field. Typical Seedance and Kling causes are reference_*_urls sent to kling-3, bitrate_mode on a model that rejects it, a duration outside the model's range, or first_frame and references mixed together. An unknown model id is 404 model_not_found.
Use a fresh Idempotency-Key whenever you change the body, since a key identifies one intended request.
What does the full table look like?
Group by the action your client should take.
| Response | Retry same request? | Action |
|---|---|---|
| 429 queue_full | Yes, with backoff | Poll existing jobs, then resubmit with the same key |
| 429 rate_limited | Yes, with backoff | Slow down request volume |
| 402 insufficient_credits | No | Top up, then resubmit |
| 400 validation error | No | Fix the named field; new key for a changed body |
| 404 model_not_found | No | Use an id from GET /v1/videos/models |
| 5xx or timeout | Yes | Same key, bounded attempts |
How do I encode it in a client?
This submit helper retries only the retryable codes, up to five times, and reuses one key across attempts.
import os, time, uuid, requests
def submit(body: dict, tries: int = 5) -> dict:
key = str(uuid.uuid4())
h = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}",
"Idempotency-Key": key}
for n in range(tries):
try:
r = requests.post("https://api.sume.com/v1/videos",
json=body, headers=h, timeout=60)
except requests.RequestException:
time.sleep(2 ** n)
continue
if r.status_code == 429 or r.status_code >= 500:
time.sleep(2 ** n)
continue
r.raise_for_status() # 400, 402, 404: fix the request
return r.json()
raise RuntimeError("gave up after retries")
if __name__ == "__main__":
print(submit({"model": "seedance-2-mini", "prompt": "A paper boat"}))
What about jobs that fail after they were accepted?
That is a different path. An accepted job that ends failed releases or refunds its reservation where applicable, and its error text is on the poll response. Do not resubmit blindly: read GET /v1/jobs/{id}/events first, since an unreachable input URL or a refused reference will fail the same way again. See video job concurrency and queueing for how pending jobs behave.
The helper uses exponential delay because Sume's docs, as read for this post, do not specify a retry interval for submit errors.
How should I log these so they are debuggable?
Log the HTTP status, the error.code, the model id and the idempotency key for every submit, and nothing from the prompt you would not want in a log. The code is the reliable field: statuses are shared, codes are stable. When you contact support, the request id from the response is the quickest handle.
Alert on a rising rate of queue_full rather than on any single occurrence. A steady trickle means your batch is larger than your plan's processing and queue capacity allow, and the fix is pacing, not retries. A spike of 400 after a deploy usually means a field was added to a request that a specific model rejects.
Sources
Related posts
More in Developers
- Seedance or Kling video 409: job_not_completed vs job_failed
A 409 from GET /v1/videos/{id}/content means two opposite things on Sume: job_not_completed is retryable, job_failed is not. How to tell them apart.
- One image to Seedance: reference, or first frame?
On Sume a single reference image with no frame field is priced and routed as reference-to-video; add a first frame to get image-to-video. How to choose.
- Seedance size parameter returns 400 on Sume: use resolution
Sending size such as 1280x720 to /v1/videos returns 400 unsupported_parameter on Sume. Use resolution plus aspect_ratio instead.
- Seedance on Video Router or /v1/videos: which endpoint for new code
Sume says new Seedance integrations should use POST /v1/videos. Video Router still works unchanged with the same ids. Here is the field difference.
Written by Sume