timeline_must_start_at_zero and transition_on_first_segment fixes
Timeline 1.0 needs video[0].start to be 0 and no transition on slot 0. How to open on a fade or a later in-point, with a Python builder that runs.

Timeline 1.0 refuses a document whose first video slot does not start at 0 (timeline_must_start_at_zero) or whose first slot carries a transition (transition_on_first_segment). Set video[0].start to 0 and remove its transition. To begin partway into a file use source_in, and to open from black use output.fade_in_seconds.
Why can't the first slot have a transition?
A transition describes the boundary into a slot from the one before it. Slot 0 has no predecessor, so there is nothing to blend with. The Timeline 1.0 page lists the type as legal only on slots after the first, and says video[0].start must be 0 with later starts increasing.
The start field is a position on the audio spine, not a position in the source file. If your first clip should begin at 12 s of the file, that is source_in: 12, while start stays 0.
| I want | Use | Not |
|---|---|---|
| First clip begins 12 s into its file | video[0].source_in = 12 | video[0].start = 12 |
| Open from black | output.fade_in_seconds (0 to 5) | video[0].transition |
| Cross-fade clip 1 into clip 2 | video[1].transition | video[0].transition |
| Only a section of a long file | Video trim first, or source_in plus duration | A negative start |
How is this different from an FFmpeg concat list?
FFmpeg's concat approaches take an ordered list and never ask where the first clip sits on a clock. Sume's Timeline is built around an audio spine, so every slot is placed on that clock and the first one anchors it. The in-point inside the file is a separate field, which is the same split FFmpeg makes between -ss on an input and the position in the output.
Output edge fades are separate again: output.fade_in_seconds and output.fade_out_seconds accept 0 to 5 s and their sum cannot exceed the output length, otherwise the render refuses with edge_fades_exceed_output.
How do I build a valid video[] array?
Accumulate durations for the starts, and add a fade only from the second slot onward. The Python below does that and prints the starts together with the audio length you need. It uses placeholder artifact URLs in the shape of the documentation examples.
Every source_url must be a media.sume.com artifact or asset in your workspace, so import external files first. Then check the document with the unbilled POST /v1/timeline-1.0/plan call before the render.
def build(durations, fade=0.0):
video, t = [], 0.0
for i, d in enumerate(durations):
slot = {"source_url": f"https://media.sume.com/artifacts/artf_demo/c{i}.mp4",
"start": round(t, 3), "duration": d}
if i and fade:
slot["transition"] = {"type": "fade", "duration": fade}
video.append(slot)
t += d
return video
video = build([8, 6, 10], fade=0.25)
assert video[0]["start"] == 0 and "transition" not in video[0]
total = video[-1]["start"] + video[-1]["duration"]
print([s["start"] for s in video], "audio.duration_seconds >=", total - 0.5)What else trips the first slot?
A still as slot 0 is fine: stills are held for the slot duration, and any motion on a still is ignored with a motion_ignored warning. A slot shorter than 0.2 s is refused. And the spine must exist: audio.duration_seconds is required, from 1 to 1800 seconds, even in silence mode.
What does a correct first slot look like?
A slot is a source_url, a start on the spine, a duration, and optional fields such as source_in, fit and motion. For the first one, the minimal valid form is start: 0, a positive duration of at least 0.2 s, and no transition. If a script generator emits a transition for every slot by habit, strip it from index 0 in the same function that sets the start.
If the opening needs a branded sting rather than a fade, make it its own first slot, a short clip or still, and start the main footage in slot 1 with a transition from there. That keeps both rules satisfied and gives the cross-fade something to blend with.
How do I test a generated timeline?
Add two assertions to the unit test that covers your builder: the first slot's start equals 0 and the first slot has no transition key. They are cheap, they run offline, and they catch the two refusals before a request is made.
Then keep the unbilled plan call in an integration test with a small fixture document. It returns duration_seconds, segment_count and an estimate, so you can also assert that the length you expect is the length the API computed.
Sources
Related posts
More in Developers
- Timeline segment_overlap: set start times when clips cross-fade
Sume Timeline returns segment_overlap when a slot starts before the previous one ends minus the fade. The rule, the fix, and a Python check.
- Timeline transition_too_long: 1 s cap and half the shorter clip
transition_too_long means a Timeline fade is over 1 s or over half the shorter neighbour. Sub-frame fades fail too. Limits, snapping, and a check.
- Transactional outbox for paid API calls in Python (Sume)
Write the Sume request and its Idempotency-Key in the order's transaction, drain later: a tested Python outbox that survives crashes, 429s and 409s.
- Transcribe a three-hour recording when the API caps at ten minutes
Streaming sessions end at an hour; Sume STT jobs take up to 600 seconds. Split with Timeline audio, transcribe 18 chunks, and stitch word times back together.
Written by Sume