compose_duration_clamped_to_source: the banner clip came out shorter

Compose clamps video.duration to the source file and warns compose_duration_clamped_to_source. The job still succeeds; read the result length first.

4 min readSume
All posts

compose_duration_clamped_to_source is a warning, not a failure. It means you asked Timeline compose for a video.duration longer than the file has left, so Sume clamped it to the end of the source and the job still succeeded. The output is shorter than you asked for, and the number to trust is the duration_seconds in the result.

Why it happens

Compose takes the output length from the video layer only: video.duration, or else the rest of the file from video.source_in. The still never changes the length. The ceiling is 300 seconds. So a 10-second request on a 6-second clip gives a 6-second MP4 and the warning, and a source_in of 4 on the same clip leaves 2 seconds.

In a Black Friday workflow this shows up when a banner is composed over a short generated clip and then placed into a longer timeline slot. The timeline slot says 10 seconds, the composed shot is 6, and the rest of the slot is a problem.

Compose duration behavior from the Sume docs, read 2026-10-05
You sendOutput lengthWarning
video.duration within the fileAs requestednone
video.duration past the end of the fileRest of the filecompose_duration_clamped_to_source
No duration, with source_inRest of the file after source_innone
Any requestNever more than 300 snone

Read the result, then plan the slot

The job result for compose returns video_url and duration_seconds. Use that number, not your request, when you declare the next Timeline slot. The script below submits a compose with an over-long duration, then prints the real length and the warnings. It is a $0.02 flat job.

Whether the warning object is a string or an object in your response, print it whole and match on the code text.

import json, os, time, urllib.request

def call(path, body=None, key=None):
    h = {"Authorization": "Bearer " + os.environ["SUME_API_KEY"], "Content-Type": "application/json"}
    if key:
        h["Idempotency-Key"] = key
    data = json.dumps(body).encode() if body else None
    return json.load(urllib.request.urlopen(urllib.request.Request("https://api.sume.com" + path, data, h)))

def run(path, body, key):
    jid = call(path, body, key)["request_id"]
    while call(f"/v1/jobs/{jid}/status")["status"] not in ("completed", "failed", "canceled"):
        time.sleep(5)
    return call(f"/v1/jobs/{jid}/result")

M = "https://media.sume.com/artifacts/artf_demo/"
out = run("/v1/timeline-1.0/compose", {"operation": "overlay",
          "image": {"url": M + "sale-banner.png"},
          "video": {"url": M + "six-second-clip.mp4", "duration": 10}}, "banner-v1")
print(out["duration_seconds"], out.get("warnings"))
# Use out["duration_seconds"] for the Timeline slot, not the 10 you asked for.

What Timeline does with a short source

If you put a 6-second shot into a 10-second slot anyway, Timeline 1.0 does not fail. The docs say soft warnings include padded or looped short sources, and that a plan cannot predict those warnings. So the render can succeed with a held or looped tail that you did not intend, which on a sale clip means the price card sits there too long or repeats.

Fixes

  • Set the slot duration to the composed duration_seconds.
  • Or generate or trim the source to at least the length you need before composing.
  • Or lengthen the shot by adding a second slot rather than asking compose for more than the file has.
  • Treat any compose warning as a review item in your build, not a silent pass.

Limits

Clamping only happens on the duration. A still that is not a still, or a file that is not a video, fails with its own codes (compose_image_not_still, compose_video_not_video).

Sources

Related posts

More in Developers

All Developers posts

Written by Sume