affaan-m/ECC · error · ValueError

clip ( ) has non-positive duration

Error message

clip {i} ({path}) has non-positive duration {dur!r}

What it means

timeline.py raises ValueError('clip {i} ({path}) has non-positive duration {dur!r}') in _normalise when a clip's duration is 0 or negative. Durations must be positive so each event occupies at least one frame in the output timeline.

Solutions

  1. Provide a positive 'duration' in seconds for each clip.
  2. Probe actual media durations (ffprobe) instead of hardcoding 0.
  3. Guard before building: `assert all(c.get('duration', 0) > 0 for c in clips)`.
  4. Fix unit conversion so durations are seconds, not frames or milliseconds misread.

Example fix

// before
{"path": "a.mp4", "duration": 0}
// after
{"path": "a.mp4", "duration": 5.0}
Defensive patterns

Strategy: validation

Validate before calling

def validate_clip_durations(clips):
    for i, c in enumerate(clips):
        try:
            dur = float(c.get('duration') or 0.0)
        except (TypeError, ValueError):
            raise ValueError(f'clip {i} duration not numeric')
        if dur <= 0:
            raise ValueError(f'clip {i} non-positive duration {dur!r}')
    return True

Type guard

def has_positive_duration(c) -> bool:
    try:
        return float(c.get('duration') or 0.0) > 0
    except (TypeError, ValueError):
        return False

Try / catch

try:
    edl = build_edl(clips, fps=30)
except ValueError as e:
    if 'non-positive duration' in str(e):
        logger.error('bad duration in clips: %s', e)
        raise

Prevention

When it happens

Trigger: Calling build_fcpxml/build_edl with a clip whose 'duration' is 0, missing (defaults to 0.0), negative, or a non-numeric string that float() coerces oddly.

Common situations: Duration computed from a failed metadata probe returning 0; placeholder clips with duration 0; unit mistakes (frames given where seconds expected producing 0 after rounding); missing 'duration' key entirely.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/f6c0370c5bcafc4f. Report an issue: GitHub.

Appendix: source

Thrown at skills/taste-application/scripts/taste/timeline.py:221

# ---------------------------------------------------------------------------


def _normalise(clips: Iterable[dict], fps: float | Fraction) -> list[dict]:
    """Validate clips and pre-compute integer frame counts and offsets.

    Returns dicts with ``path``, ``name``, ``frames`` (int, >= 1) and
    ``offset_frames`` (int). Working in frames from here down is what makes the
    sequence duration exactly the sum of the clip durations.
    """
    out: list[dict] = []
    offset = 0
    for i, c in enumerate(clips):
        path = str(c.get("path") or "")
        if not path:
            raise ValueError(f"clip {i} has no 'path'")
        dur = float(c.get("duration") or 0.0)
        if dur <= 0:
            raise ValueError(f"clip {i} ({path}) has non-positive duration {dur!r}")
        frames = max(1, seconds_to_frames(dur, fps))  # never emit a zero-length event
        name = str(c.get("name") or Path(path).stem)
        out.append(
            {
                "path": path,
                "name": name,
                "frames": frames,
                "offset_frames": offset,
                "seconds": dur,
            }
        )
        offset += frames
    if not out:
        raise ValueError("no clips to write - a timeline needs at least one event")
    return out


def _file_uri(path: str) -> str:

View on GitHub (pinned to 8321021c54)