Comfy-Org/ComfyUI · error · ValueError
Number of texts ({len(texts)}) does not match number of imag
Error message
Number of texts ({len(texts)}) does not match number of images ({num_images}). Text list should have length {num_images}, 1, or 0. What it means
Thrown by the image+text dataset-encoding node when the text list length is neither 0/None (treated as unconditional), nor 1 (broadcast to all images), nor exactly the number of images. The node intentionally supports only these three shapes before it VAE-encodes the images.
Source
Thrown at comfy_extras/nodes_dataset.py:1901
@classmethod
def execute(cls, images, vae, clip, texts=None):
# Extract scalars (vae and clip are single values wrapped in lists)
vae = vae[0]
clip = clip[0]
# Handle text list
num_images = len(images)
if texts is None or len(texts) == 0:
# Treat as [""] for unconditional training
texts = [""]
if len(texts) == 1 and num_images > 1:
# Repeat single text for all images
texts = texts * num_images
elif len(texts) != num_images:
raise ValueError(
f"Number of texts ({len(texts)}) does not match number of images ({num_images}). "
f"Text list should have length {num_images}, 1, or 0."
)
# Encode images with VAE
logging.info(f"Encoding {num_images} images with VAE...")
latents_list = [] # list[{"samples": tensor}]
for img_tensor in images:
# img_tensor is [1, H, W, 3]
latent_tensor = vae.encode(img_tensor[:, :, :, :3])
latents_list.append({"samples": latent_tensor})
# Encode texts with CLIP
logging.info(f"Encoding {len(texts)} texts with CLIP...")
conditioning_list = [] # list[list[cond]]
for text in texts:
if text == "":
cond = clip.encode_from_tokens_scheduled(clip.tokenize(""))View on GitHub (pinned to 1c6d8d45b3)
Solutions
- Make len(texts) equal len(images), or pass exactly one caption to broadcast, or an empty list/None for unconditional.
- Rebuild the caption list from the same filtered image list (zip images and caption files together when loading).
- Print both lengths before the node to find which side drifted.
Example fix
# before texts = load_captions(folder) # 5 entries images = load_images(folder) # 7 after filtering # after images = load_images(folder) texts = [captions[img.stem] for img in images] # guaranteed same length
Defensive patterns
Strategy: validation
Validate before calling
n = len(images)
if texts is None or len(texts) == 0:
texts = [''] # unconditional
elif len(texts) == 1 and n > 1:
texts = texts * n # broadcast
assert len(texts) == n, f'texts={len(texts)} but images={n}' Type guard
def texts_match_images(texts: list[str] | None, n: int) -> bool:
return texts is None or len(texts) in (0, 1, n) Prevention
- Build the caption list by zipping over the final (filtered) image list so lengths cannot drift.
- Remember the three accepted shapes: 0/None, 1, or exactly len(images).
- Re-generate captions after changing any image filter.
When it happens
Trigger: Passing e.g. 5 captions for 7 images, or 7 captions for 5 images, into the texts input. Also passing a list-of-lists or nested structure that changes len(texts).
Common situations: Caption files (txt sidecars, CSV columns) that don't align 1:1 with images after filtering; manually curated caption lists where entries were added or deleted; image lists modified by resolution filtering after captions were loaded.
Related errors
- Number of latents ({len(latents)}) does not match number of
- Number of latents ({len(latents)}) does not match number of
- INVALID_TAG_FILTER
- Connect at least one keyframe image.
- Spreading {len(images)} images across the clip needs an expl
AI-assisted analysis of Comfy-Org/ComfyUI@1c6d8d45b3 (2026-08-14).
Data as JSON: /api/errors/1708eb5a8e628608.
Report an issue: GitHub.