invoke-ai/InvokeAI · error · ValueError

prompt has {num_text_tokens} tokens, exceeds max_text_tokens

Error message

prompt has {num_text_tokens} tokens, exceeds max_text_tokens={max_text_tokens}

What it means

encode_qwen3vl_prompt tokenizes the prompt through the Qwen3-VL chat template and refuses prompts whose token count exceeds max_text_tokens, since longer sequences would exceed the model's context/positional budget for text conditioning.

Source

Thrown at invokeai/backend/ideogram4/text_encoding.py:48

    """Encode a single prompt into Ideogram 4 conditioning features.

    Returns a ``(num_text_tokens, 53248)`` float32 tensor (on the encoder's device;
    the caller is responsible for moving it to CPU for storage).
    """
    # Importing here keeps module import cheap and tolerant of transformers versions
    # that lay out the masking utilities differently.
    from transformers.masking_utils import create_causal_mask

    device = next(text_encoder.parameters()).device

    # Chat-format and tokenize, matching Ideogram4Pipeline._tokenize.
    messages = [{"role": "user", "content": [{"type": "text", "text": prompt}]}]
    text = tokenizer.apply_chat_template(messages, add_generation_prompt=True, tokenize=False)
    encoded = tokenizer(text, return_tensors="pt", add_special_tokens=False)
    token_ids = encoded["input_ids"].to(device)  # (1, L)
    num_text_tokens = int(token_ids.shape[1])
    if num_text_tokens > max_text_tokens:
        raise ValueError(f"prompt has {num_text_tokens} tokens, exceeds max_text_tokens={max_text_tokens}")

    # Text-only sequence: every position is a real LLM token.
    attention_mask = torch.ones((1, num_text_tokens), dtype=torch.long, device=device)
    pos_2d = torch.arange(num_text_tokens, device=device)[None, :]  # (1, L)

    language_model = text_encoder.language_model
    inputs_embeds = language_model.embed_tokens(token_ids)

    position_ids_4d = pos_2d[None, ...].expand(4, 1, num_text_tokens)
    text_position_ids = position_ids_4d[0]  # (1, L)
    mrope_position_ids = position_ids_4d[1:]  # (3, 1, L)

    causal_mask = create_causal_mask(
        config=language_model.config,
        inputs_embeds=inputs_embeds,
        attention_mask=attention_mask,
        past_key_values=None,
        position_ids=text_position_ids,

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Shorten the prompt until it fits within max_text_tokens
  2. Increase max_text_tokens if the model/config allows a larger text budget
  3. Count tokens first with the tokenizer and trim before calling
  4. Reduce chat-template overhead by checking what apply_chat_template adds

Example fix

# before
encode_qwen3vl_prompt(tokenizer, very_long_prompt, max_text_tokens=256)
# after
n = len(tokenizer(very_long_prompt).input_ids)
assert n <= 256, f"trim prompt: {n} tokens"
encode_qwen3vl_prompt(tokenizer, trim(very_long_prompt, 256), max_text_tokens=256)
Defensive patterns

Strategy: validation

Validate before calling

encoded = tokenizer(prompt, add_special_tokens=False)
if len(encoded.input_ids) + CHAT_TEMPLATE_OVERHEAD > max_text_tokens:
    prompt = truncate_prompt_to_tokens(prompt, max_text_tokens)

Try / catch

try:
    result = encode_qwen3vl_prompt(tokenizer, prompt, max_text_tokens, device)
except ValueError as e:
    if "exceeds max_text_tokens" in str(e):
        prompt = truncate_prompt_to_tokens(prompt, max_text_tokens)
        result = encode_qwen3vl_prompt(tokenizer, prompt, max_text_tokens, device)
    else:
        raise

Prevention

When it happens

Trigger: Calling invoke with a very long prompt (or prompt+chat-template overhead) whose tokenized length exceeds max_text_tokens.

Common situations: Long descriptive prompts pasted from elsewhere, chat template adding system/generation tokens the user didn't count, small max_text_tokens configured for speed, non-English text tokenizing to more tokens.

Related errors


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/10454be6bafdb74a. Report an issue: GitHub.