SumeMediaFile duration_ms is checked within 10% of the real file
A duration_ms in Format output must match the run's artifact ledger within 10%, or the projection fails. A null means not measured, not zero.

The duration_ms inside a SumeMediaFile in a Format run's output is checked against the file. It comes off the same ledger that fills artifacts[], and where that ledger recorded a length, your value must agree with it within 10%. A value that does not is treated as describing a different file, and the projection fails instead of reaching you. Where the ledger recorded no length, nothing is checked, and null means "not measured", never zero.
What is checked, and what is not?
Only the duration on a media object is held to the file. A number you declare yourself elsewhere in the schema is written by the projection from the run's own account, with no such check. The table separates the two.
| Field | Checked against the file? | What null means |
|---|---|---|
duration_ms inside a SumeMediaFile | Yes, within 10% where the ledger recorded a length | Not measured |
A duration_seconds number you declared in your own schema | No: written by the projection | Whatever your schema allows |
artifacts[].duration_ms on the receipt | This is the ledger the check reads | Not measured |
Why 10% and not exact?
The docs state the tolerance and the reason: a claim that is off by more than that describes a different file. The gate allows a margin and fails only on a mismatch large enough to suggest the wrong asset.
The rule also keeps null honest. Where the ledger did not record a length, the run is not failed over a fact nobody measured. So a duration_ms you read back is either the artifact's own or unverified, and never a number computed from something else.
How should I use the checked value?
Treat output.<key>.duration_ms as trustworthy only when it is non-null, and fall back to the matching artifacts[] entry when you need a number for billing or scheduling. If a pipeline needs a hard length, validate it on your side against the downloaded file; Sume's check promises agreement with its own ledger, not a probe of your download.
This command reads the receipt and prints the primary key next to the lengths of the video artifacts, so you can compare them with the media object in output.
curl -sS "https://api.sume.com/v1/format-runs/$RUN_ID/result" \
-H "Authorization: Bearer $SUME_API_KEY" \
| jq '{
status: .data.status,
primary_output_key: .data.primary_output_key,
artifact_ms: [.data.artifacts[] | select(.type == "video") | .duration_ms]
}'What happens when the check fails?
The projection fails the same way a bad URL does: output is null, output_error explains it, and the run is failed when it was created over the API, because those runs are unattended and a completed receipt with an empty output would read as a success. artifacts[] is populated either way, so the media is not lost. Check output_error before reading output, and loosen or drop a duration field you cannot trust rather than retrying blindly.
Prefer a nullable union for the field in your own schema, as for any optional value: every property must be listed in required, and null is how a run says it had nothing to put there.
Sources
Related posts
More in Formats
- Sume SDK subscribeFormatRun: 20-minute timeout vs 90-minute runs
subscribeFormatRun in @sume-com/sdk polls every 2 seconds and times out at 20 minutes by default, while a Format run can live 90. Set the timeout on purpose.
- sume-virtual-try-on Format: first frame, then Seedance 2.5
The sume-virtual-try-on Format builds a first frame with ChatGPT Image 2, then animates it with Seedance 2.5. What goes in, what comes back.
- Sume webhook retry schedule: 30s doubling, 10 tries, 1h cap
Sume Format run webhooks retry up to 10 times with min(max(30s x 2^(attempt-1), Retry-After), 1h). The arithmetic of that schedule and what to do when it ends.
- TikTok's Next Episode: a brand series as one Format and one queue
TikTok's The Next Episode funds creator-led series. Here is how to produce a season with Sume: one Format recipe, one bulk queue of up to 100 runs.
Written by Sume