invoke-ai/InvokeAI · error · ValueError
encode_caption_for_pid requires at least one caption.
Error message
encode_caption_for_pid requires at least one caption.
What it means
encode_caption_for_pid encodes a non-empty list of captions for the PiD decoder; the padded-token mask is essential to correct output, so encoding zero captions is rejected outright with ValueError.
Source
Thrown at invokeai/backend/pid/decode.py:598
encoder: "object", # Gemma2Model
device: torch.device,
dtype: torch.dtype = torch.bfloat16,
chi_prompt: str = PID_CHI_PROMPT,
model_max_length: int = PID_MODEL_MAX_LENGTH,
) -> tuple[Tensor, Tensor]:
"""Mirror of `PixelDiTModel._encode_text_raw`.
Prepends the chi-prompt, tokenises with right-padding, runs Gemma's
`model` (the transformer stack without the LM head), and selects
``[CLS] + last (model_max_length - 1)`` tokens to yield a fixed
``[B, model_max_length, 2304]`` embedding plus the matching attention
mask. The mask is critical: PidNet's joint attention zeros padded text
tokens out via this mask. Without it the decoder treats all ~300 slots
(including the padding) as valid caption tokens and produces a
washed-out average image.
"""
if not captions:
raise ValueError("encode_caption_for_pid requires at least one caption.")
n_chi_tokens = len(tokenizer.encode(chi_prompt)) if chi_prompt else 0
prompts = [chi_prompt + c for c in captions]
max_len = (n_chi_tokens + model_max_length - 2) if chi_prompt else model_max_length
# PiD was trained with right-padding (see PixelDiTModel._load_text_encoder
# upstream). Gemma2's tokenizer defaults to "left" which would push the
# BOS token away from index 0 and shove pads into the slice the decoder
# consumes — yielding a garbled caption embedding. We toggle the value
# for the duration of this call and restore it afterwards so we don't
# poison the shared cached tokenizer.
old_padding_side = getattr(tokenizer, "padding_side", "right")
try:
tokenizer.padding_side = "right"
toks = tokenizer(
prompts,
max_length=max_len,
padding="max_length",
truncation=True,
return_tensors="pt",View on GitHub (pinned to 0b6a024f2f)
Solutions
- Ensure at least one non-empty caption string is passed in the captions list
- Fix upstream prompt sanitization so it substitutes a default prompt instead of dropping all prompts
- Add a caller-side check: if not captions: use a fallback prompt
Example fix
// before embs = encode_caption_for_pid(tok, te, captions=[]) // after captions = captions or [""] embs = encode_caption_for_pid(tok, te, captions=captions)
Defensive patterns
Strategy: validation
Validate before calling
if not captions:
captions = [default_prompt]
embs = encode_caption_for_pid(tokenizer, text_encoder, captions=captions, chi_prompt=chi_prompt) Type guard
def has_captions(captions) -> bool:
return bool(captions) and all(isinstance(c, str) for c in captions) Try / catch
try:
embs = encode_caption_for_pid(tok, te, captions=captions, chi_prompt=chi)
except ValueError:
embs = encode_caption_for_pid(tok, te, captions=[default_prompt], chi_prompt=chi) Prevention
- Never filter prompt lists down to empty — substitute a default
- Sanitize upstream prompt nodes to always emit at least one string
- Log dropped prompts so silent empty-list cases surface early
When it happens
Trigger: Calling encode_caption_for_pid(tokenizer, text_encoder, captions=[], ...) — an empty list (or empty container) of captions.
Common situations: A prompt-processing node upstream producing an empty prompt list after filtering blank prompts; a batched invoke where all prompts were dropped; a caller passing None coerced to an empty list.
Related errors
- Cannot create an image move job with no items
- Unknown image subfolder strategy: {strategy}
- Invalid external model source: '{source_stripped}'
- Invalid or expired token
- User not found or inactive
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/10a09d3d5ceec689.
Report an issue: GitHub.