Comfy-Org/ComfyUI · error · ValueError

Aleph2 accepts either keyframes or prompt images, not both.

Error message

Aleph2 accepts either keyframes or prompt images, not both.

What it means

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.

Source

Thrown at comfy_api_nodes/nodes_runway.py:779

        public_figure_threshold: str = "low",
        keyframes: RunwayAleph2KeyframeChain | None = None,
        prompt_images: RunwayAleph2PromptImageChain | None = None,
    ) -> IO.NodeOutput:
        validate_string(prompt, min_length=1, max_length=1000)
        validate_video_duration(
            video,
            min_duration=2.0,
            max_duration=30.0,
        )
        try:
            fps = float(video.get_frame_rate())
        except Exception:
            fps = None
        if fps is not None and fps > 30.0 + 0.01:
            raise ValueError(f"Input video frame rate ({fps:.2f} fps) exceeds Aleph2's maximum of 30 fps.")

        if (keyframes and keyframes.items) and (prompt_images and prompt_images.items):
            raise ValueError("Aleph2 accepts either keyframes or prompt images, not both.")

        video_duration: float | None = None
        try:
            video_duration = video.get_duration()
        except Exception:
            video_duration = None

        def _check_seconds(value: float, label: str) -> None:
            if video_duration is not None and value > video_duration + 0.0001:
                raise ValueError(f"{label} {value:.2f}s exceeds the input video duration ({video_duration:.2f}s).")

        video_url = await upload_video_to_comfyapi(cls, video)

        keyframe_models: list[RunwayAleph2KeyframeSeconds | RunwayAleph2KeyframeAt] = []
        if keyframes is not None:
            if len(keyframes.items) > 5:
                raise ValueError("Aleph2 supports at most 5 keyframes.")
            for item in keyframes.items:

View on GitHub (pinned to 1c6d8d45b3)

Solutions

  1. Disconnect one of the two inputs — pass either keyframes OR prompt images
  2. If both kinds of guidance are needed, run two separate Aleph2 generations

Example fix

// before
aleph2(prompt, video, keyframes=kf, prompt_images=pi)

// after
aleph2(prompt, video, keyframes=kf)  // or prompt_images=pi, not both
Defensive patterns

Strategy: validation

Validate before calling

has_keyframes = keyframes is not None and bool(keyframes.items)
has_prompt_images = prompt_images is not None and bool(prompt_images.items)
assert not (has_keyframes and has_prompt_images), "Aleph2: pass keyframes OR prompt_images, not both"

Type guard

def aleph2_guidance_valid(keyframes, prompt_images) -> bool:
    kf = bool(keyframes and keyframes.items)
    pi = bool(prompt_images and prompt_images.items)
    return not (kf and pi)

Try / catch

try:
    await aleph2_execute(...)
except ValueError as e:
    if "not both" in str(e):
        prompt_images = None  # or keyframes = None, then retry
        await aleph2_execute(...)
    else:
        raise

Prevention

When it happens

Trigger: Connecting both RunwayAleph2KeyframeNode output and RunwayAleph2PromptImageNode output (each with .items non-empty) to the Aleph2 video node simultaneously.

Common situations: Building a workflow incrementally and forgetting to disconnect the earlier guidance input; copying a graph that wires both inputs for documentation purposes.

Related errors


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