An uploaded Sume asset you never complete: what happens
A pending_upload asset has a 15-minute URL by default. After the window and a one-hour grace, a reaper deletes the object and marks the row failed.

If you PUT bytes to a Sume upload URL and never call complete, the asset stays pending_upload until the URL window closes (900 seconds by default). Completing after that returns 409 asset_upload_expired and deletes the object. A background reaper then removes anything left more than an hour past the window: it deletes the stored object and moves the row to failed. These routes are implemented but hidden from the public OpenAPI document, so treat them as a working surface rather than a documented contract; for generation inputs Sume's docs still prefer public HTTPS media URLs.
The numbers below are defaults from the API configuration and reaper code on Sume's main branch, read 2026-10-11.
How long is the upload window?
The upload-url response includes upload.expires_at and upload.max_bytes. The window defaults to 900 seconds, and the byte limit defaults to 2 GiB; both are deployment settings. The same expires_at is stored on the asset as upload.expires_at, so a later GET /v1/assets/{id} shows when the window closes.
A request over the byte limit never gets a URL: upload-url answers 413 asset_too_large before creating anything.
What does the reaper do?
Before the reaper existed, an upload that was PUT and never completed kept its row in pending_upload and its bytes in the media bucket forever. Now every tick lists pending rows whose window closed more than 60 minutes ago, in batches of 100 with at most 10 batches per tick.
For each row it deletes the object first and only then marks the row failed. A failed delete leaves the row pending so the next tick retries. If another live row points at the same object key, which happens when a thread is forked, the object is kept and only the expired row is failed. The tick runs every 10 minutes by default, and setting the interval to 0 turns it off.
| Time after upload-url | State |
|---|---|
| 0 to 15 minutes | pending_upload, PUT and complete allowed |
| After 15 minutes | complete returns 409 asset_upload_expired and deletes the object |
| After about 75 minutes | eligible for the reaper on its next tick |
| After the reaper runs | object deleted, status failed |
How do I find and clean up pending uploads?
List with status=pending_upload to see uploads still open, and status=failed to see what the reaper closed. Nothing needs to be done for an abandoned upload; the reaper handles it. If your job still needs the file, request a new upload URL and start again, because an expired asset cannot be revived.
Completion of a ready asset is idempotent and returns the asset again, so retrying a complete call whose response you lost is safe.
curl -s "https://api.sume.com/v1/assets?status=pending_upload&limit=100" \
-H "Authorization: Bearer $SUME_API_KEY" \
| jq -r '.data.assets[] | [.id, .upload.expires_at] | @tsv'Sources
Related posts
More in Developers
- Sume generation_capacity_exhausted: the 503, job reason and flag
Sume reports provider capacity three ways: HTTP 503 provider_capacity_exceeded, a job reason generation_capacity_exhausted, and a sync flag. All three retry.
- Sume job failed artifact_too_large: shrink the output, don't rerun
A Sume job failing with artifact_too_large or artifact_upload_rejected made its file but could not store it. Make the file smaller; rerunning changes nothing.
- Sume job failed worker_job_stalled or worker_lease_expired: what now
A Sume job stuck in processing can end as worker_job_stalled or worker_lease_expired. Both are terminal job.failed events with the hold refunded. Resubmit.
- Sume queue_admission_unavailable and usage_reservation_unavailable
Two Sume submit failures that are not 402 or 429: admission or the usage hold could not be evaluated. The row is failed and refunded; retry with the same key.
Written by Sume