{"record":{"id":"47fe683f88dd62a5","repo":"Comfy-Org/ComfyUI","slug":"ratios-must-be-positive-got-a-b","errorCode":null,"errorMessage":"Ratios must be positive, got {a}:{b}.","messagePattern":"Ratios must be positive, got (.+?):(.+?)\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"comfy_api_nodes/util/validation_utils.py","lineNumber":205,"sourceCode":"            f\"Field '{field_name}' cannot be shorter than {min_length} characters; was {len(string)} characters long.\"\n        )\n    if max_length and len(string) > max_length:\n        raise Exception(\n            f\" Field '{field_name} cannot be longer than {max_length} characters; was {len(string)} characters long.\"\n        )\n\n\ndef validate_container_format_is_mp4(video: Input.Video) -> None:\n    \"\"\"Validates video container format is MP4.\"\"\"\n    container_format = video.get_container_format()\n    if container_format not in [\"mp4\", \"mov,mp4,m4a,3gp,3g2,mj2\"]:\n        raise ValueError(f\"Only MP4 container format supported. Got: {container_format}\")\n\n\ndef _ratio_from_tuple(r: tuple[float, float]) -> float:\n    a, b = r\n    if a <= 0 or b <= 0:\n        raise ValueError(f\"Ratios must be positive, got {a}:{b}.\")\n    return a / b\n\n\ndef _assert_ratio_bounds(\n    ar: float,\n    *,\n    min_ratio: tuple[float, float] | None = None,\n    max_ratio: tuple[float, float] | None = None,\n    strict: bool = True,\n) -> None:\n    \"\"\"Validate a numeric aspect ratio against optional min/max ratio bounds.\"\"\"\n    lo = _ratio_from_tuple(min_ratio) if min_ratio is not None else None\n    hi = _ratio_from_tuple(max_ratio) if max_ratio is not None else None\n\n    if lo is not None and hi is not None and lo > hi:\n        lo, hi = hi, lo  # normalize order if caller swapped them\n\n    if lo is not None:","sourceCodeStart":187,"sourceCodeEnd":223,"githubUrl":"https://github.com/Comfy-Org/ComfyUI/blob/1c6d8d45b3693bfbb32385b410d813a7fd6be216/comfy_api_nodes/util/validation_utils.py#L187-L223","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["If you are the node author: fix the bound tuple to positive values; use None instead of 0 to mean 'no bound'.","If unbounded is intended on one side, pass min_ratio=None / max_ratio=None rather than a degenerate tuple.","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.","Double-check ratio order conventions (w:h vs h:w) against the validator's callers before editing."],"exampleFix":"# before\n_ratio_from_tuple((0, 1))  # ValueError: Ratios must be positive, got 0:1.\n\n# after\nbounds = None  # no lower bound\n_ratio_from_tuple((1, 4))  # valid lower bound","handlingStrategy":"validation","validationCode":"def valid_ratio_bound(t):\n    return t is None or (isinstance(t, tuple) and len(t) == 2 and all(x > 0 for x in t))","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Node authors: pass None for unbounded sides instead of degenerate tuples.","Unit-test bound tuples with positive components.","Never translate '0:1' from provider docs literally into code."],"tags":["api-nodes","validation","aspect-ratio","developer-error"],"backgroundTag":null,"analyzedSha":"1c6d8d45b3693bfbb32385b410d813a7fd6be216","analyzedAt":"2026-08-14T19:37:18.893Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}