affaan-m/ECC · error · ValueError

explicit opacity must be finite within 0..100

Error message

explicit opacity must be finite within 0..100

What it means

When a placement event includes an 'opacity' key, allocate_placements requires it to be a non-bool int/float that is finite (not NaN/inf) and within 0..100; otherwise it raises ValueError('explicit opacity must be finite within 0..100'). Strings like '50' are rejected — opacity must be numeric.

Solutions

  1. Supply opacity as a plain number between 0 and 100 (e.g. 50, 87.5), not a string or bool
  2. Validate/convert at the boundary: `o = float(raw); assert 0 <= o <= 100 and math.isfinite(o)`
  3. Fix upstream math that produced NaN/inf (division by zero, log of negative) before assigning opacity
  4. Omit the 'opacity' key entirely if you want the default rather than passing None

Example fix

// before
{"id": "logo", "opacity": "50"}
// after
{"id": "logo", "opacity": 50}
Defensive patterns

Strategy: validation

Validate before calling

import math

def valid_opacity(v):
    return (not isinstance(v, bool)
            and isinstance(v, (int, float))
            and math.isfinite(v)
            and 0 <= v <= 100)

assert valid_opacity(50)

Type guard

def is_opacity(v) -> bool:
    return isinstance(v, (int, float)) and not isinstance(v, bool) and math.isfinite(v) and 0 <= v <= 100

Try / catch

try:
    resolve.allocate_placements(fps, count, placements)
except ValueError as e:
    if 'opacity' in str(e):
        raise PlacementError(f'bad opacity value in placements') from e
    raise

Prevention

When it happens

Trigger: Passing opacity='50' (string), opacity=True/False, opacity=None, NaN or float('inf') (e.g. from a bad JSON config or a division by zero upstream), or opacity=150.

Common situations: Config where opacity was entered as a percentage string; JSON parser can't produce NaN but Python float('nan') from upstream math can; a script computing opacity by division that yielded inf/nan; leaving opacity as a boolean toggle.

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/6fba0d3371ef7fc2. Report an issue: GitHub.

Appendix: source

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

    """
    rate = _fps(fps)
    _integer(base_track_count, "base_track_count")
    checked, seen, metadata = [], set(), {}
    for event in placements:
        identifier = event.get("id")
        if not isinstance(identifier, str) or not identifier or identifier in seen:
            raise ValueError("placement id must be unique and nonempty")
        seen.add(identifier)
        start = _integer(event.get("record_frame"), "record_frame")
        frames = _integer(event.get("frames"), "frames", 1)
        opacity = event.get("opacity")
        if (
            isinstance(opacity, bool)
            or not isinstance(opacity, (int, float))
            or not math.isfinite(opacity)
            or not 0 <= opacity <= 100
        ):
            raise ValueError("explicit opacity must be finite within 0..100")
        composite = _integer(event.get("composite"), "composite")
        raw_asset = event.get("asset")
        if not isinstance(raw_asset, (str, Path)) or not str(raw_asset):
            raise ValueError("asset must be a local regular file")
        asset = Path(raw_asset).expanduser().resolve()
        if not asset.is_file():
            raise ValueError(f"asset must be a local regular file: {asset}")
        alpha = event.get("requires_alpha", False)
        if not isinstance(alpha, bool):
            raise ValueError("requires_alpha must be boolean")
        key = str(asset)
        if key not in metadata:
            metadata[key] = probe(asset)
        info = metadata[key]
        if _fps(info.get("fps")) != rate:
            raise ValueError(f"asset fps differs from timeline: {asset}")
        if _integer(info.get("frames"), "asset frames", 1) < frames:
            raise ValueError(f"asset contains too few frames: {asset}")

View on GitHub (pinned to 8321021c54)