invoke-ai/InvokeAI · critical · RuntimeError

Qwen3-VL encoder did not return hidden_states; cannot build

Error message

Qwen3-VL encoder did not return hidden_states; cannot build Krea-2 conditioning.

What it means

This RuntimeError is thrown in _encode of the krea2_text_encoder invocation when the Qwen3-VL text encoder's forward output contains no hidden_states, neither at the top level nor nested under language_model_outputs. Krea-2 conditioning requires tapping 12 decoder hidden-state layers (KREA2_SELECT_LAYERS) to build the (B, seq, 12, hidden) tensor, so without hidden states conditioning cannot be constructed at all. It is guarded even though output_hidden_states=True is passed, because different VL model wrappers expose the output differently.

Source

Thrown at invokeai/app/invocations/krea2_text_encoder.py:147

            position_ids = (attention_mask.long().cumsum(dim=-1) - 1).clamp(min=0)
            position_ids = position_ids.unsqueeze(0).expand(3, -1, -1)

            outputs = text_encoder(
                input_ids=input_ids,
                attention_mask=attention_mask,
                position_ids=position_ids,
                output_hidden_states=True,
                use_cache=False,
                return_dict=True,
            )

            # Some VL models nest the language-model output; fall back to that if needed.
            hidden_states_tuple = getattr(outputs, "hidden_states", None)
            if hidden_states_tuple is None:
                lm_output = getattr(outputs, "language_model_outputs", None)
                hidden_states_tuple = getattr(lm_output, "hidden_states", None)
            if hidden_states_tuple is None:
                raise RuntimeError("Qwen3-VL encoder did not return hidden_states; cannot build Krea-2 conditioning.")

            # Stack the selected layers along a new layer axis: (B, seq, 12, hidden).
            stacked = torch.stack([hidden_states_tuple[i] for i in KREA2_SELECT_LAYERS], dim=2)

            # Drop the system-prompt prefix tokens.
            prompt_embeds = stacked[:, KREA2_START_IDX:]
            prompt_mask = attention_mask[:, KREA2_START_IDX:].bool()

            # Match the device-safe compute dtype used by the denoise loop (falls back from bf16 to
            # fp16/fp32 on devices without bf16 support) rather than forcing bfloat16.
            prompt_embeds = prompt_embeds.to(dtype=TorchDevice.choose_bfloat16_safe_dtype(device))

        return prompt_embeds, prompt_mask

    def _lora_iterator(self, context: InvocationContext) -> Iterator[PatchSpec]:
        """Iterate over the LoRA models to apply to the Qwen3-VL text encoder."""
        for lora in self.qwen3_vl_encoder.loras:
            lora_info = context.models.load(lora.lora)

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Verify the model connected to qwen3_vl_encoder is the correct Qwen3-VL text encoder for Krea-2, not a different or renamed checkpoint.
  2. Upgrade diffusers/transformers to the version InvokeAI expects, so the Qwen3-VL output exposes hidden_states (directly or on language_model_outputs).
  3. Check that any custom wrapper around the encoder forwards output_hidden_states=True and returns a ModelOutput containing hidden_states.
  4. As a diagnostic, print type(outputs) and dir(outputs) after the forward call to see where hidden states actually live, and extend the fallback chain.

Example fix

// before
class MyEncoderWrapper(nn.Module):
    def forward(self, input_ids, attention_mask, position_ids, **kw):
        return self.lm(input_ids=input_ids, attention_mask=attention_mask, position_ids=position_ids)
// after
class MyEncoderWrapper(nn.Module):
    def forward(self, input_ids, attention_mask, position_ids, **kw):
        return self.lm(input_ids=input_ids, attention_mask=attention_mask,
                       position_ids=position_ids, output_hidden_states=True, return_dict=True)
Defensive patterns

Strategy: try-catch

Validate before calling

// Before invoking, sanity-check the loaded encoder model class/config
enc_info = context.models.load(self.qwen3_vl_encoder.text_encoder)
if "qwen3" not in enc_info.config.base.name.lower() or "vl" not in enc_info.config.base.name.lower():
    raise ValueError(f"Expected a Qwen3-VL text encoder, got {enc_info.config.base}")

Type guard

def has_hidden_states(outputs: object) -> bool:
    hs = getattr(outputs, "hidden_states", None)
    if hs is not None:
        return True
    lm = getattr(outputs, "language_model_outputs", None)
    return lm is not None and getattr(lm, "hidden_states", None) is not None

Try / catch

try:
    prompt_embeds, prompt_mask = krea2_text_encoder.invoke(context)
except RuntimeError as e:
    if "did not return hidden_states" in str(e):
        logger.error("Text encoder is not a compatible Qwen3-VL model; check the encoder model and library versions.")
        raise
    raise

Prevention

When it happens

Trigger: Calling the krea2_text_encoder invocation with a text encoder whose forward() returns an object lacking both .hidden_states and .language_model_outputs.hidden_states — e.g. a wrong or incompatible model loaded into the Qwen3-VL encoder slot, a custom/subclassed encoder that ignores output_hidden_states=True, or an older diffusers/transformers version whose Qwen3-VL output class does not expose hidden_states under either attribute name.

Common situations: Users point the Krea-2 text-encoder node at a plain Qwen3 (non-VL) or other LLM checkpoint whose ModelConfig does not match; library upgrades rename or nest the output attributes; custom wrapper code strips ModelOutput fields via use_cache/return_dict combinations or a custom forward that never sets output_hidden_states.

Related errors


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