Last frame of an AI video clip: fix frame_time_out_of_range
To chain AI video clips, take the last frame of clip one as the first frame of clip two. Ask video-frames for a time below the duration, not equal to it.

The short answer
To chain AI video clips, extract the last frame of clip one with POST /v1/video-frames and use it as the next clip's first_frame. Every at value must satisfy 0 <= t < duration, so asking for the exact duration fails with frame_time_out_of_range. Ask for a time slightly before the end instead, such as 0.1 seconds earlier.
Why the error happens
The rule in the docs is that each at time must be at least 0 and strictly less than the probed duration. If it is not, the worker fails the job with frame_time_out_of_range and gives you the probed duration. A 5-second request can produce a file that is a hair longer or shorter than 5 seconds, so treating the requested duration as the file duration is the usual cause.
Request
First import the clip to the Sume media host if it is not there (the route rejects other hosts), then submit. The route always returns 202; poll the video-frames GET. The source_duration_seconds field in the result is what the worker probed.
curl -X POST https://api.sume.com/v1/video-frames \
-H "Authorization: Bearer $SUME_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: lastframe-001" \
-d '{
"video_url": "https://media.sume.com/artifacts/artf_demo/clip1.mp4",
"at": [4.8],
"format": "png"
}'Pick a time below the end
A 5-second clip with a margin of 0.2 seconds uses 4.8. A margin that small is not visible in a chained shot. If you do not know the length, run video inspect first, which returns probe facts, then subtract the margin from the probed duration.
Use the frame
The result lists frames[{t, url, width, height}] with durable image URLs. If extraction fails for one instant, that frame has url set to null, and the job itself does not fail, so check each frame before using it. Use the url as the next clip's first_frame.
Limits and cost
Billing is by the job's own compute and not by a fixed rate, so the cost of a single-frame grab is small next to a clip. The route takes up to 24 times in one call and clips up to 300 seconds.
Keep chains short
A chain drifts. Each clip is a new generation of the last frame, so faces and colors change a little every hop. Keep chains short, or lock the subject with reference images on models that take them.
Sources
Related posts
More in Developers
- video_inspect: fps 2 and a 24-still cap cover only 12 seconds
At fps 2 video_inspect's 24-still cap covers 12 seconds. Pick fps or explicit at[] times by clip length; a table of coverage from 12 s to 96 s per call.
- video_inspect seek fast vs precise: a quick look with keyframe stills
seek: fast moves each still to the keyframe at or before its instant and skips the decode. Use it for a quick look; precise when timing matters.
- Video job statuses: pending, cancelled vs Sume's five job states
A /v1/videos job says pending or in_progress; /v1/jobs/{id}/status says queued or processing. Here is the mapping, which one to poll, and the spelling trap.
- Video model fallback chain in Python with one key per model
A Python chain that tries Gemini Omni, Wan 3.0 and Seedance 2 on Sume in order, stops on 401 or 402, and uses a separate idempotency key for each model.
Written by Sume