Comfy-Org/ComfyUI · error · ValueError

Ratios must be positive, got {a}:{b}.

Error message

Ratios must be positive, got {a}:{b}.

What it means

Raised by the private helper _ratio_from_tuple() in comfy_api_nodes/util/validation_utils.py when a min_ratio/max_ratio bound tuple contains a zero or negative component. This is developer/config error, not user input error: the tuples are hardcoded by node authors to define provider aspect-ratio limits (e.g. (1, 4) meaning 1:4), and X:Y must have X,Y > 0.

Source

Thrown at comfy_api_nodes/util/validation_utils.py:205

            f"Field '{field_name}' cannot be shorter than {min_length} characters; was {len(string)} characters long."
        )
    if max_length and len(string) > max_length:
        raise Exception(
            f" Field '{field_name} cannot be longer than {max_length} characters; was {len(string)} characters long."
        )


def validate_container_format_is_mp4(video: Input.Video) -> None:
    """Validates video container format is MP4."""
    container_format = video.get_container_format()
    if container_format not in ["mp4", "mov,mp4,m4a,3gp,3g2,mj2"]:
        raise ValueError(f"Only MP4 container format supported. Got: {container_format}")


def _ratio_from_tuple(r: tuple[float, float]) -> float:
    a, b = r
    if a <= 0 or b <= 0:
        raise ValueError(f"Ratios must be positive, got {a}:{b}.")
    return a / b


def _assert_ratio_bounds(
    ar: float,
    *,
    min_ratio: tuple[float, float] | None = None,
    max_ratio: tuple[float, float] | None = None,
    strict: bool = True,
) -> None:
    """Validate a numeric aspect ratio against optional min/max ratio bounds."""
    lo = _ratio_from_tuple(min_ratio) if min_ratio is not None else None
    hi = _ratio_from_tuple(max_ratio) if max_ratio is not None else None

    if lo is not None and hi is not None and lo > hi:
        lo, hi = hi, lo  # normalize order if caller swapped them

    if lo is not None:

View on GitHub (pinned to 1c6d8d45b3)

Solutions

  1. If you are the node author: fix the bound tuple to positive values; use None instead of 0 to mean 'no bound'.
  2. If unbounded is intended on one side, pass min_ratio=None / max_ratio=None rather than a degenerate tuple.
  3. If you are a user hitting this from a third-party node, update the node pack — it is a bug in the node, not your input; report it upstream with the traceback.
  4. Double-check ratio order conventions (w:h vs h:w) against the validator's callers before editing.

Example fix

# before
_ratio_from_tuple((0, 1))  # ValueError: Ratios must be positive, got 0:1.

# after
bounds = None  # no lower bound
_ratio_from_tuple((1, 4))  # valid lower bound
Defensive patterns

Strategy: validation

Validate before calling

def valid_ratio_bound(t):
    return t is None or (isinstance(t, tuple) and len(t) == 2 and all(x > 0 for x in t))

Prevention

When it happens

Trigger: A node implementation calls validate_aspect_ratio(..., min_ratio=(0, 1)) or max_ratio=(16, -9)) — a typo or a mistaken 'allow zero width' assumption. End users essentially cannot trigger it via widgets because bounds are baked into the node code.

Common situations: Custom-node authors copying provider docs that express limits as '0:1 to 1:0' (meaning fully unbounded) and passing them literally; refactor typos swapping a ratio for a dimension; or tests feeding synthetic bound tuples.

Related errors


AI-assisted analysis of Comfy-Org/ComfyUI@1c6d8d45b3 (2026-08-14). Data as JSON: /api/errors/47fe683f88dd62a5. Report an issue: GitHub.