A failed Sume video poll has error as a string, not an error object
On /v1/videos, HTTP errors use {error:{code,message}} but a failed poll carries error as a string. Read both without a TypeError in Python and TypeScript.

A 200 poll with status failed carries error as a plain string, while a real HTTP error such as 402 or 429 carries an envelope {error:{code,message,request_id,details}}. Code that reads poll.error.message on a failed job gets undefined in TypeScript or a TypeError in Python.
Two places an error can live
The poll body is a bare object with id, generation_id, polling_url, status, model, unsigned_urls, usage and error. When the job failed, error is the text. When the poll request itself fails, you get a non-2xx status and the envelope.
Handle both, and log the x-sume-request-id response header on the second case; the string case has no code to branch on.
| Situation | HTTP status | Where | Shape |
|---|---|---|---|
| Job failed | 200 | poll body, error | string |
| Not enough balance | 402 | response body, error | object with code and message |
| Too many requests | 429 | response body, error | object, error.details.scope |
| Content before completion | 409 | response body, error | object, job_not_completed or job_failed |
A reader that handles both
The function returns one string for logs and never raises on shape.
def error_text(status_code, body):
err = body.get("error")
if isinstance(err, str):
return err # failed poll: plain text
if isinstance(err, dict):
code = err.get("code", "error")
return f"{status_code} {code}: {err.get('message', '')}"
return f"{status_code} unknown error"
# poll = requests.get(polling_url, headers=h)
# if poll.json()["status"] == "failed":
# print(error_text(poll.status_code, poll.json()))Gotchas
A failed job is not a reason to resubmit blindly: check the text first. A bad input URL is fixed by changing the input, and each resubmit of a 30 s Wan 3.0 clip at 720p reserves $3.75 again, so three blind tries reserve 3 x $3.75 = $11.25.
The docs sample uses status.get('error', 'Unknown error') in Python and status.error ?? 'Unknown error' in TypeScript, which is the same idea in one line.
Sources
Related posts
More in Developers
- ffprobe check for Gemini Omni reference videos: 3 files, 3 s each
Before sending reference videos to Sume's gemini-omni-flash-1.1, check with ffprobe that you have one to three files and each is 3.0 s or shorter. Bash script.
- Find callers still sending nano-banana-2 or gemini-3.1-flash-image
Sume runs the retired nano-banana-2 id as Nano Banana 2.1 and echoes your id back. A repo scan finds stale ids and gemini-3.1-flash-image before you migrate.
- Find exhausted Sume webhook deliveries and redeliver them in Python
Page GET /v1/jobs for completed and failed jobs, keep webhook_delivery.status exhausted, and call POST /v1/jobs/{id}/webhook/redeliver for each.
- First and last frame video API call: Wan 3.0, 6 s at 720p, $0.75
A working first-frame and last-frame request for Sume's /v1/videos: Wan 3.0, 6 seconds, 720p, $0.75. Which rows accept last_frame and which do not.
Written by Sume