Sume asset upload errors: 413, 409 size mismatch, expired
Direct asset uploads on Sume fail with 413 asset_too_large or 409 asset_upload_incomplete, asset_size_mismatch and asset_upload_expired. Fixes for each.

A Sume direct upload is three steps: POST /v1/assets/upload-url, a PUT of the bytes, then POST /v1/assets/{id}/complete. Errors map to a step. 413 asset_too_large is the declared size. 409 asset_upload_incomplete is a missing object. 409 asset_size_mismatch is bytes that differ from the declared size. 409 asset_upload_expired is a PUT after the window closed.
Error to cause to fix
| Code | Step | Cause | Fix |
|---|---|---|---|
413 asset_too_large | upload-url or complete | Declared or stored size is over the limit (default 2 GiB) | Compress or split, then request a new URL |
409 asset_upload_incomplete | complete | No object at the key yet | PUT the file first, then call complete |
409 asset_size_mismatch | complete | Stored length differs from the declared size_bytes | Re-request a URL with the true size and upload again |
409 asset_upload_expired | complete | The upload URL window closed (default 900 seconds) | Request a fresh URL; the old object is deleted |
409 asset_checksum_mismatch | complete | The completion checksum differs from the declared one | Send the same checksum_sha256 or omit it |
Why the PUT is picky
The signed URL pins the content length to the size_bytes you declared, so storage refuses a PUT of any other size. At completion Sume trusts only the length that storage reports for the stored object, not the number in the completion body. A rejected completion deletes the object, and the row stays pending_upload, so a retry means a new upload-url call.
Abandoned uploads are cleaned up
If you PUT and never call complete, a reaper picks up the row once it is more than an hour past its upload window. It deletes the object first and only then marks the row failed. A failed delete leaves the row pending for the next tick. The default interval is 10 minutes. An object that another live row still points at, for example after a thread fork, is kept.
The checksum is a label, not proof
checksum_sha256 on an uploaded asset is the value you declared at upload-url. Storage does not verify SHA-256 on a single PUT and Sume does not hash the bytes, so treat it as caller-declared metadata. Completion never adopts a checksum that first appears in the completion request.
When you do not need uploads
Generation fields such as input.image_url take a public HTTPS URL directly. Reserve the upload flow for files that are not public. Registering a remote URL with POST /v1/assets stores unverified metadata only: status registered, no first-party URL, and no fetch or dimension check.
A retry pattern that works
Treat each upload as an atomic attempt. Stat the file, call upload-url with the true size, PUT with the exact bytes and the content type you declared, then call complete. On any 409 from complete, start again from upload-url rather than re-calling complete, because a rejected completion removes the object. On 413, change the file, not the code. Keep the returned asset id only after complete succeeds, since a pending_upload row is not usable as a generation input and will eventually be reaped. Download links are short-lived as well, with a 300 second default, so fetch them when you need them.
Operators can change three knobs through environment variables: the maximum upload bytes, the upload URL lifetime in seconds, and the reaper interval in milliseconds, where zero turns the reaper off. As a client you cannot set them, so read the max_bytes value in the 413 body rather than hard-coding 2 GiB. The same body returns your size_bytes, which makes the gap obvious in a log line.
Related posts
More in Developers
- Why sume/auto returns 400 for 21:9, not a Seedance route
sume/auto accepts 3 to 10 s in 16:9 or 9:16. Ask for 21:9 or 15 s and you get 400 unsupported_capability, not a quiet reroute to Seedance.
- sume/auto vs a pinned video model: three jobs where each wins
sume/auto is right for an 8-second 720p clip at $1.00. A 12-second or 20-second clip needs a pinned id, because auto resolves to Omni with a 10-second cap.
- Which Sume calls cost nothing: checks, plans and failed images
Several Sume calls are free: video_filter check_only, timeline plan, hypit compose output check, and failed or cancelled image generations. Lint before you pay.
- Sume CLI avatar-videos batch: plan, create, watch, result
The Sume CLI batches avatar videos in four steps against local state files. What each step does, and why the per-item idempotency key makes reruns safe.
Written by Sume