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.

4 min readSume
All posts

A Timeline 1.0 transition must be 1.0 s or shorter and no more than 50% of the shorter of the two slots it joins. Anything longer returns 400 transition_too_long, and the error carries a max_seconds value so you can retry with it. A fade shorter than one output frame returns transition_not_frame_aligned instead of silently turning into a hard cut.

What are the exact limits?

These come from the Timeline 1.0 page and the API source (apps/api/src/timeline.ts). The cap is min(1, 0.5 * min(previous.duration, current.duration)). A 1.2 s slot next to an 8 s slot therefore allows at most 0.6 s, while two 8 s slots allow the full 1 s.

Fades are rendered as a whole number of frames. A duration that is off the frame lattice is snapped, and the job still succeeds with a transition_snapped_to_frame warning that reports the requested and applied seconds. At 24 fps, 0.3 s is 7.2 frames and renders as 7 frames (0.292 s).

Transition limits on Timeline 1.0, read 2026-10-03 from the Timeline 1.0 page and API source
RuleValueResult when broken
Longest transition1.0 stransition_too_long
Share of the shorter neighbour50%transition_too_long
Shortest transitionat least one output frametransition_not_frame_aligned
Consecutive transitions8 without a hard cuttoo_many_chained_transitions
On the first slotnot allowedtransition_on_first_segment
Typesfade, wipeleft, wiperight, slideup, slidedown, dissolveschema error

Why is it stricter than FFmpeg's xfade?

The FFmpeg filters documentation lets xfade duration run from 0 to 60 seconds with a default of 1 second. Sume narrows that, because a long fade eats the clips on both sides and a chain of long fades leaves the chunk planner nowhere to split. The source comment on the chained-fade cap says as much: offsets accumulate in one graph.

When the frame rate is omitted from output.fps, the API checks the fade against the slowest allowed rate, 24 fps, because the real rate is only known from the sources at render time. Sending at least 1/fps seconds is the safe floor.

How do I choose a legal duration in code?

Clamp before you build the request. The helper below returns the largest legal fade for a pair of slots and tells you whether a requested fade survives as at least one frame. It runs with the standard library only.

If a fade is too long for a short slot, cut to a hard cut by omitting transition on that slot, or lengthen the slot's duration. A hard cut is always valid; a run of more than 8 fades is not.

def max_transition(prev_len, cur_len):
    return min(1.0, 0.5 * min(prev_len, cur_len))

def min_frames_ok(seconds, fps):
    return round(seconds * fps) >= 1

print(max_transition(8, 1.2))      # 0.6
print(max_transition(8, 8))        # 1.0
for fps in (24, 25, 30, 60):
    print(fps, min_frames_ok(0.02, fps), min_frames_ok(1 / fps, fps))

Where do I see the clamp before paying?

Send the document to POST /v1/timeline-1.0/plan first. It is unbilled, runs the same checks, and returns the refusal with its next_action (shorten_transition, use_frame_aligned_transition or insert_hard_cut). Then submit the render with an Idempotency-Key, so a retried request does not queue a second job.

What if I want a longer dissolve?

Lengthen the neighbouring slots, not the fade. Because the cap is half the shorter side, two slots of 2 s or more both allow a full 1 s fade, and 1 s is the ceiling for every type. If a design needs something slower, a still held for a few seconds between two clips gives each fade room, and fade_in_seconds and fade_out_seconds on output (0 to 5 s each) cover the opening and closing edges without touching the slot rules.

When a fade is clamped by the API rather than refused, you will see it in the warnings of the finished render. Treat those warnings as a to-do list: each one names the slot and the applied value, so fixing the source document is a small edit.

How does the plan call help here?

The plan response is the cheapest place to learn a fade is too long. It returns the refusal body, including max_seconds, without a job, without reserving credits and without downloading any media. A common pattern is to run the plan, read the cap, clamp the value in your builder, and only then send the render with an Idempotency-Key.

Because the plan runs the same compiler checks as the render, a document that plans cleanly will not fail on transitions later. The warnings that remain are the ones that depend on the real files, such as a source shorter than its slot.

Sources

Related posts

More in Developers

All Developers posts

Written by Sume