affaan-m/ECC · error · ContractError
genre has invalid total duration
Error message
genre {spec.get('number')} has invalid total duration What it means
When a spec's measured_features contains total_duration, it must be a finite real number. _is_finite_real rejects None, non-numeric types, NaN, and infinity. The validator raises this ContractError so downstream timing math never operates on missing or non-finite durations.
Solutions
- Ensure the measurement pipeline produces a real finite float for total_duration and fix the NaN/inf source (often a division by zero).
- Parse string durations: total_duration = float(raw) after validating it is numeric.
- If no duration is known yet, omit the key or set measured_features to None rather than passing NaN.
- Add math.isfinite(total_duration) at the point where evidence is recorded to fail early.
Example fix
// before
spec["measured_features"]["total_duration"] = float("nan")
// after
import math
duration = compute_duration()
assert math.isfinite(duration) and duration > 0
spec["measured_features"]["total_duration"] = duration Defensive patterns
Strategy: validation
Validate before calling
import math
def duration_is_finite(spec):
m = spec.get("measured_features") or {}
d = m.get("total_duration")
return isinstance(d, (int, float)) and not isinstance(d, bool) and math.isfinite(d) Type guard
def is_finite_duration(value) -> bool:
return isinstance(value, (int, float)) and not isinstance(value, bool) and math.isfinite(value) Try / catch
try:
validate_genre_specs(specs)
except ContractError as e:
if "invalid total duration" in str(e):
for s in specs:
d = (s.get("measured_features") or {}).get("total_duration")
if not math.isfinite(float(d)):
raise ValueError(f"re-measure spec {s.get('number')}: duration={d!r}")
raise Prevention
- Fail fast with math.isfinite() where the duration is measured.
- Investigate NaN/inf sources — usually division by zero in the measurement code.
- Never serialize float('inf') or float('nan') into evidence files.
- Parse quoted duration strings to float before storing.
When it happens
Trigger: Calling validate_genre_specs / validate_bundle with measured_features containing total_duration set to None, a string like "3.5", NaN/inf (e.g. from a failed measurement or 0-division), or the key holding a non-numeric object.
Common situations: A measurement step that failed and wrote NaN (e.g. dividing by zero duration); JSON configs where total_duration was quoted as a string; missing key resolved via .get to None; serialization of float('inf') from earlier computations.
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
- clip ( ) has non-positive duration
- clip ( ) has non-positive duration
- clip ( ) has non-positive duration
- receipt reference has an invalid finite source duration
- reference probe duration must be finite and positive
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/c021a3d64556ec9d.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/tasteforge/contract.py:140
if len(numbers) != len(set(numbers)):
raise ContractError("genre numbers must be distinct")
fingerprints = [spec.get("style_fingerprint") for spec in specs]
signatures = [_semantic_signature(spec) for spec in specs]
if len(fingerprints) != len(set(fingerprints)) or len(signatures) != len(set(signatures)):
raise ContractError("genre references collapsed into a generic style; distinct specs required")
for spec in specs:
if spec.get("dry_run") is not True:
raise ContractError(f"genre {spec.get('number')} crosses the dry-run boundary")
measured = spec.get("measured_features")
if measured is not None:
if not isinstance(measured, dict):
raise ContractError(f"genre {spec.get('number')} has invalid measured evidence")
_validate_numeric_evidence(measured, label=f"genre {spec.get('number')} evidence")
total_duration = measured.get("total_duration")
if not _is_finite_real(total_duration):
raise ContractError(f"genre {spec.get('number')} has invalid total duration")
total_duration = cast(float, total_duration)
if float(total_duration) <= 0:
raise ContractError(f"genre {spec.get('number')} has invalid total duration")
for group_name in ("sample_times",):
groups = measured.get(group_name, [])
if not isinstance(groups, list):
raise ContractError(f"genre {spec.get('number')} has invalid time evidence")
for group in groups:
if not isinstance(group, dict):
raise ContractError(f"genre {spec.get('number')} has invalid time evidence")
for time in group.get("times", []):
_validate_media_time(
time, group.get("source_duration"),
label=f"genre {spec.get('number')} time evidence",
)
temporal = measured.get("temporal", {})
if isinstance(temporal, dict):
for group in temporal.get("scene_change_evidence", []):View on GitHub (pinned to 8321021c54)