{"record":{"id":"5225a2ff11159f79","repo":"Comfy-Org/ComfyUI","slug":"exactly-one-image-is-required-got-a-batch-pick-o","errorCode":null,"errorMessage":"Exactly one image is required; got a batch. Pick one frame first.","messagePattern":"Exactly one image is required; got a batch\\. Pick one frame first\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"comfy_api_nodes/nodes_sync_so.py","lineNumber":315,"sourceCode":"                IO.Hidden.unique_id,\n            ],\n            is_api_node=True,\n            price_badge=IO.PriceBadge(\n                expr=\"\"\"{\"type\":\"usd\",\"usd\":0.19019,\"format\":{\"approximate\":true,\"suffix\":\"/second\"}}\"\"\",\n            ),\n        )\n\n    @classmethod\n    async def execute(\n        cls,\n        image: Input.Image,\n        audio: Input.Audio,\n        prompt: str,\n        seed: int,\n        model: dict,\n    ) -> IO.NodeOutput:\n        if get_number_of_images(image) != 1:\n            raise ValueError(\"Exactly one image is required; got a batch. Pick one frame first.\")\n        validate_audio_duration(audio, max_duration=600)\n\n        height, width = get_image_dimensions(image)\n        speaker_x, speaker_y = model[\"speaker_x\"], model[\"speaker_y\"]\n        if max(width, height) > 4096 or width * height > 4096 * 2160:\n            if not model[\"auto_downscale\"]:\n                raise ValueError(\n                    f\"sync.so rejects images above 4K (4096x2160); got {width}x{height}. \"\n                    \"Downscale the image first or enable auto_downscale.\"\n                )\n            image = downscale_image_tensor(image, total_pixels=4096 * 2160)\n            image = downscale_image_tensor_by_max_side(image, max_side=4096)\n            new_height, new_width = get_image_dimensions(image)\n            # speaker coordinates are given in the original image's pixel space\n            speaker_x = min(new_width - 1, round(speaker_x * new_width / width))\n            speaker_y = min(new_height - 1, round(speaker_y * new_height / height))\n\n        if model[\"speaker_selection\"] == \"coordinates\":","sourceCodeStart":297,"sourceCodeEnd":333,"githubUrl":"https://github.com/Comfy-Org/ComfyUI/blob/1c6d8d45b3693bfbb32385b410d813a7fd6be216/comfy_api_nodes/nodes_sync_so.py#L297-L333","documentation":"Raised by the sync.so Talking Image node when the image input is a batch with more than one image. The endpoint animates a single portrait, so get_number_of_images(image) must equal 1. Unlike the video lipsync node, this node can auto-downscale oversized images, but batching has no equivalent escape.","triggerScenarios":"Connecting a multi-image tensor (shape[0] > 1) to the talking-image node's image input, e.g. frames from a video or a multi-view image set.","commonSituations":"Feeding an image-generation node's batched output directly; assuming the node picks the first frame automatically; decoding a short clip as an image batch.","solutions":["Select exactly one frame from the batch upstream (slice or image-pick node)","If animating several portraits, run the node once per image"],"exampleFix":"# before\ntalking_image(image=batch_tensor, audio=a)  # 4 images\n\n# after\ntalking_image(image=batch_tensor[0:1], audio=a)  # single portrait","handlingStrategy":"validation","validationCode":"assert get_number_of_images(image) == 1, \"Talking Image needs exactly one portrait; slice the batch first\"","typeGuard":"def is_single_portrait(image) -> bool:\n    return get_number_of_images(image) == 1","tryCatchPattern":"try:\n    await syncso_talking_image(image, audio, ...)\nexcept ValueError as e:\n    if \"got a batch\" in str(e):\n        await syncso_talking_image(image[0:1], audio, ...)\n    else:\n        raise","preventionTips":["Feed exactly one portrait; loop externally if animating several","Note this node auto-downscale handles 4K images, but nothing rescues a batch"],"tags":["sync-so","image-batch","validation","talking-image"],"backgroundTag":null,"analyzedSha":"1c6d8d45b3693bfbb32385b410d813a7fd6be216","analyzedAt":"2026-08-14T19:37:18.893Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}