{"record":{"id":"32799ad303939260","repo":"Comfy-Org/ComfyUI","slug":"give-one-time-per-keyframe-image-got-len-parts","errorCode":null,"errorMessage":"Give one time per keyframe image: got {len(parts)} time(s) for {image_count} image(s).","messagePattern":"Give one time per keyframe image: got (.+?) time\\(s\\) for (.+?) image\\(s\\)\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"comfy_api_nodes/nodes_bfl.py","lineNumber":1060,"sourceCode":"    for tensor in (images or {}).values():\n        if tensor is None:\n            continue\n        if tensor.ndim == 4:\n            flat.extend(tensor[i] for i in range(tensor.shape[0]))\n        else:\n            flat.append(tensor)\n    if len(flat) > _FLUX3_MAX_IMAGES:\n        raise ValueError(f\"FLUX 3 supports at most {_FLUX3_MAX_IMAGES} {field_name}, got {len(flat)}.\")\n    for tensor in flat:\n        _flux3_validate_image(tensor)\n    return flat\n\n\ndef _flux3_parse_times(value: str, image_count: int, duration: int | str) -> list[float]:\n    \"\"\"Parse one keyframe time in seconds per image: increasing, inside the clip.\"\"\"\n    parts = [part.strip() for part in value.split(\",\") if part.strip()]\n    if len(parts) != image_count:\n        raise ValueError(\n            f\"Give one time per keyframe image: got {len(parts)} time(s) for {image_count} image(s).\"\n        )\n    try:\n        times = [float(part) for part in parts]\n    except ValueError as exc:\n        raise ValueError(f\"Keyframe times must be numbers in seconds, comma-separated; got '{value}'.\") from exc\n    if not all(math.isfinite(time) for time in times):\n        raise ValueError(f\"Keyframe times must be finite numbers in seconds; got '{value}'.\")\n    if any(later <= earlier for earlier, later in zip(times, times[1:])):\n        raise ValueError(f\"Keyframe times must increase; got {times}.\")\n    if times[0] < 0:\n        raise ValueError(f\"Keyframe times cannot be negative; got {times[0]}.\")\n    cap = _FLUX3_MAX_DURATION if duration == \"auto\" else int(duration)\n    if times[-1] > cap:\n        raise ValueError(f\"Keyframe time {times[-1]}s is past the end of a {cap}s clip.\")\n    return times\n\n","sourceCodeStart":1042,"sourceCodeEnd":1078,"githubUrl":"https://github.com/Comfy-Org/ComfyUI/blob/1c6d8d45b3693bfbb32385b410d813a7fd6be216/comfy_api_nodes/nodes_bfl.py#L1042-L1078","documentation":"FLUX 3 keyframe timing requires exactly one comma-separated time value per keyframe image. The parser splits the times string on commas, drops empty parts, and raises when the count of parsed parts differs from the number of collected keyframe images.","triggerScenarios":"Passing '0, 5' with 3 keyframe images, or trailing-comma strings like '0,5,' (empty parts are dropped, so counts shift), or forgetting to update times after adding an image.","commonSituations":"Adding/removing keyframe images without editing the times widget; copy-pasting times strings between nodes with different image counts.","solutions":["Provide exactly image_count comma-separated values, e.g. '0, 4, 8.5' for 3 images.","Re-count images after any change to the keyframe inputs and regenerate the string.","Avoid trailing commas and empty segments."],"exampleFix":"# before\nkeyframe_times = \"0, 4\"      # 3 images -> ValueError\n\n# after\nkeyframe_times = \"0, 4, 8.5\"  # one per image","handlingStrategy":"validation","validationCode":"parts = [p.strip() for p in value.split(\",\") if p.strip()]\nassert len(parts) == image_count, f\"{len(parts)} times for {image_count} images\"","typeGuard":"def times_count_matches(value: str, image_count: int) -> bool:\n    return len([p for p in value.split(\",\") if p.strip()]) == image_count","tryCatchPattern":null,"preventionTips":["Generate the times string from the image list length.","Re-check the string after adding/removing keyframe images.","Avoid trailing commas — empty parts are dropped."],"tags":["bfl","flux3","keyframes","parsing","input-validation"],"backgroundTag":null,"analyzedSha":"1c6d8d45b3693bfbb32385b410d813a7fd6be216","analyzedAt":"2026-08-14T19:37:18.893Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}