{"record":{"id":"27d9f8cbd22ba62e","repo":"Comfy-Org/ComfyUI","slug":"aleph2-accepts-either-keyframes-or-prompt-images","errorCode":null,"errorMessage":"Aleph2 accepts either keyframes or prompt images, not both.","messagePattern":"Aleph2 accepts either keyframes or prompt images, not both\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"comfy_api_nodes/nodes_runway.py","lineNumber":779,"sourceCode":"        public_figure_threshold: str = \"low\",\n        keyframes: RunwayAleph2KeyframeChain | None = None,\n        prompt_images: RunwayAleph2PromptImageChain | None = None,\n    ) -> IO.NodeOutput:\n        validate_string(prompt, min_length=1, max_length=1000)\n        validate_video_duration(\n            video,\n            min_duration=2.0,\n            max_duration=30.0,\n        )\n        try:\n            fps = float(video.get_frame_rate())\n        except Exception:\n            fps = None\n        if fps is not None and fps > 30.0 + 0.01:\n            raise ValueError(f\"Input video frame rate ({fps:.2f} fps) exceeds Aleph2's maximum of 30 fps.\")\n\n        if (keyframes and keyframes.items) and (prompt_images and prompt_images.items):\n            raise ValueError(\"Aleph2 accepts either keyframes or prompt images, not both.\")\n\n        video_duration: float | None = None\n        try:\n            video_duration = video.get_duration()\n        except Exception:\n            video_duration = None\n\n        def _check_seconds(value: float, label: str) -> None:\n            if video_duration is not None and value > video_duration + 0.0001:\n                raise ValueError(f\"{label} {value:.2f}s exceeds the input video duration ({video_duration:.2f}s).\")\n\n        video_url = await upload_video_to_comfyapi(cls, video)\n\n        keyframe_models: list[RunwayAleph2KeyframeSeconds | RunwayAleph2KeyframeAt] = []\n        if keyframes is not None:\n            if len(keyframes.items) > 5:\n                raise ValueError(\"Aleph2 supports at most 5 keyframes.\")\n            for item in keyframes.items:","sourceCodeStart":761,"sourceCodeEnd":797,"githubUrl":"https://github.com/Comfy-Org/ComfyUI/blob/1c6d8d45b3693bfbb32385b410d813a7fd6be216/comfy_api_nodes/nodes_runway.py#L761-L797","documentation":"Raised by the Aleph2 node when both the keyframes input and the prompt_images input are connected with non-empty item lists. The Runway Aleph2 API accepts only one of these guidance mechanisms per request, so the node enforces mutual exclusion before uploading anything.","triggerScenarios":"Connecting both RunwayAleph2KeyframeNode output and RunwayAleph2PromptImageNode output (each with .items non-empty) to the Aleph2 video node simultaneously.","commonSituations":"Building a workflow incrementally and forgetting to disconnect the earlier guidance input; copying a graph that wires both inputs for documentation purposes.","solutions":["Disconnect one of the two inputs — pass either keyframes OR prompt images","If both kinds of guidance are needed, run two separate Aleph2 generations"],"exampleFix":"// before\naleph2(prompt, video, keyframes=kf, prompt_images=pi)\n\n// after\naleph2(prompt, video, keyframes=kf)  // or prompt_images=pi, not both","handlingStrategy":"validation","validationCode":"has_keyframes = keyframes is not None and bool(keyframes.items)\nhas_prompt_images = prompt_images is not None and bool(prompt_images.items)\nassert not (has_keyframes and has_prompt_images), \"Aleph2: pass keyframes OR prompt_images, not both\"","typeGuard":"def aleph2_guidance_valid(keyframes, prompt_images) -> bool:\n    kf = bool(keyframes and keyframes.items)\n    pi = bool(prompt_images and prompt_images.items)\n    return not (kf and pi)","tryCatchPattern":"try:\n    await aleph2_execute(...)\nexcept ValueError as e:\n    if \"not both\" in str(e):\n        prompt_images = None  # or keyframes = None, then retry\n        await aleph2_execute(...)\n    else:\n        raise","preventionTips":["Wire exactly one guidance input in Aleph2 graphs","Disconnect unused guidance links instead of leaving empty collections attached"],"tags":["runway","aleph2","mutual-exclusion","validation"],"backgroundTag":null,"analyzedSha":"1c6d8d45b3693bfbb32385b410d813a7fd6be216","analyzedAt":"2026-08-14T19:37:18.893Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}