affaan-m/ECC · error · ValueError

clip ( ) has non-positive duration

Error message

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

What it means

normalise_clips requires every clip to have a strictly positive duration; duration defaults to 0.0 when missing. If clip i's duration is missing, zero, negative, or non-numeric-coercible to <= 0, it raises ValueError naming the clip index, path, and offending duration. Zero/negative durations would produce empty or invalid timeline events.

Solutions

  1. Ensure each clip has a positive numeric duration in seconds before export
  2. Convert timecode strings (HH:MM:SS) to seconds before passing clips
  3. Pre-validate and filter clips: `float(c.get("duration") or 0) > 0`
  4. Fix upstream arithmetic producing negative durations (e.g. end < start)

Example fix

// before
clips = [{"path": "/media/a.mov", "duration": 0}]
// after
clips = [{"path": "/media/a.mov", "duration": 5.0}]
Defensive patterns

Strategy: validation

Validate before calling

def clips_have_positive_durations(clips: list[dict]) -> list[int]:
    bad = []
    for i, c in enumerate(clips):
        try:
            if float(c.get("duration") or 0.0) <= 0:
                bad.append(i)
        except (TypeError, ValueError):
            bad.append(i)
    return bad

Type guard

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

Try / catch

try:
    edl = build_edl(clips, fps=24)
except ValueError as e:
    if "non-positive duration" in str(e):
        print(e)  # names clip index, path, and bad duration
    raise

Prevention

When it happens

Trigger: Calling build_fcpxml/build_edl with a clip lacking 'duration' (coerced to 0.0), duration=0, a negative duration, or a string like "abc" that makes float() fail-adjacent logic produce invalid values — e.g. frames computed from a bad duration.

Common situations: CSV/JSON imports with blank duration cells, durations expressed as "00:00:05" timecodes instead of seconds, unit mix-ups (milliseconds fed as seconds can pass but produce wrong frames; negatives indicate bad subtraction upstream).

Understand the failure class

Background: "invalid duration" / "failed to parse duration": why your timeout, interval, or TTL string is rejected and which formats each library accepts — this error's family across 32 libraries.

Related errors


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

Appendix: source

Thrown at skills/taste-application/scripts/tasteforge/export.py:57

# ---------------------------------------------------------------------------
# clip normalisation
# ---------------------------------------------------------------------------

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

    Each clip is ``{"path": str, "duration": float, "name": str?}``.
    """
    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 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)