affaan-m/ECC · error · ValueError

invalid fps

Error message

invalid fps

What it means

This is the ValueError('invalid fps') raised from _fps's except clause when converting the value via float(Fraction(str(value))) fails with TypeError, ZeroDivisionError, or OverflowError. It means the fps value's string form could not be interpreted as a rational/decimal number at all (e.g. a rational with zero denominator, or a non-numeric type).

Solutions

  1. Inspect the exact fps value being passed and confirm str(value) parses as a rational (e.g. '30', '29.97', '30000/1001')
  2. Never pass rationals with zero denominator; sanitize or reject 'N/0' inputs before calling
  3. Pass plain numbers (30, 29.97) instead of exotic objects so str() conversion is safe
  4. Catch this ValueError at the call site and surface which placement/config supplied the bad fps

Example fix

# before
fps = stream_metadata['rate']  # '5/0'
resolve.allocate_placements(plan, placements, fps=fps)
# after
num, den = (int(x) for x in stream_metadata['rate'].split('/'))
if den == 0:
    raise ValueError(f'bad frame rate in source metadata: {stream_metadata["rate"]}')
resolve.allocate_placements(plan, placements, fps=f'{num}/{den}')
Defensive patterns

Strategy: validation

Validate before calling

from fractions import Fraction

def parse_fps(value):
    try:
        return float(Fraction(str(value)))
    except (ValueError, ZeroDivisionError, OverflowError, TypeError):
        return None

assert parse_fps('30000/1001') is not None

Try / catch

try:
    resolve.plan(placements, fps=raw_fps)
except ValueError as e:
    if str(e) == 'invalid fps':
        raise ConfigError(f'cannot parse fps: {raw_fps!r}') from e
    raise

Prevention

When it happens

Trigger: Passing fps values whose str() is not a parseable rational: Fraction('1/0') raising ZeroDivisionError, an object whose str() is non-numeric raising ValueError→TypeError path, or an absurdly large value raising OverflowError on float().

Common situations: Rational strings with zero denominator from malformed ffprobe data ('0/0' denominator path handled elsewhere, '5/0' here); passing a dict or list as fps; extremely large numbers exceeding float range.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at skills/taste-application/scripts/tasteforge/resolve.py:36

from .timeline import fps_fraction


def _integer(value, label, minimum=0):
    if isinstance(value, bool) or not isinstance(value, int) or value < minimum:
        raise ValueError(f"{label} must be an integer >= {minimum}")
    return value


def _fps(value):
    if isinstance(value, bool):
        raise ValueError("fps must be finite and positive")
    try:
        number = float(Fraction(str(value)))
        if not math.isfinite(number) or number <= 0:
            raise ValueError("fps must be finite and positive")
        return fps_fraction(number)
    except (TypeError, ZeroDivisionError, OverflowError) as exc:
        raise ValueError("invalid fps") from exc


def probe_asset(path):
    """Count decoded video frames; never infer source length from duration."""
    result = subprocess.run(
        [
            "ffprobe",
            "-v",
            "error",
            "-select_streams",
            "v:0",
            "-count_frames",
            "-show_entries",
            "stream=avg_frame_rate,r_frame_rate,nb_read_frames,pix_fmt",
            "-of",
            "json",
            str(path),
        ],

View on GitHub (pinned to 8321021c54)