sgl-project/sglang · error · ValueError

Expected encoder_outputs to be a list when select_layers is

Error message

Expected encoder_outputs to be a list when select_layers is provided

What it means

With select_layers, resolve_visual_encoder_outputs expects encoder_outputs to be the list of per-layer hidden states (length num_loaded_layers+1). If a single tensor (final output only) is passed, selected layer indices cannot be extracted and it raises this ValueError.

Source

Thrown at python/sglang/srt/models/siglip2.py:396

    post_layer_norm: Optional[nn.LayerNorm],
    select_layers: Optional[list[int]] = None,
    max_possible_layers: Optional[int] = None,
) -> torch.Tensor:
    """Resolve outputs from visual encoder based on select_layers."""
    if select_layers is None:
        if isinstance(encoder_outputs, list):
            encoder_outputs = encoder_outputs[-1]
        if post_layer_norm is not None:
            encoder_outputs = post_layer_norm(encoder_outputs)
        return encoder_outputs

    if max_possible_layers is None:
        raise ValueError(
            "`max_possible_layers` must be provided alongside `select_layers`"
        )

    if not isinstance(encoder_outputs, list):
        raise ValueError(
            "Expected encoder_outputs to be a list when select_layers is provided"
        )

    # Get the hidden states corresponding to the layer indices
    num_loaded_layers = len(encoder_outputs) - 1
    offset = max_possible_layers - num_loaded_layers
    hs_pool = [
        (
            encoder_outputs[layer_idx]
            if layer_idx >= 0
            else encoder_outputs[layer_idx + offset]
        )
        for layer_idx in select_layers
    ]

    uses_last_layer = select_layers[-1] in (max_possible_layers - 1, -1)
    if post_layer_norm is not None and uses_last_layer:
        hs_pool[-1] = post_layer_norm(hs_pool[-1])

View on GitHub (pinned to 0132848349)

Solutions

  1. Ensure the encoder is invoked in a mode that returns all per-layer outputs (list) when select_layers is used
  2. Pass the raw list before any `encoder_outputs[-1]`-style reduction
  3. Drop select_layers if only the final layer is needed

Example fix

# before
feats = resolve_visual_encoder_outputs(final_tensor, select_layers=[5,17], max_possible_layers=27)
# after
feats = resolve_visual_encoder_outputs(all_layer_outputs, select_layers=[5,17], max_possible_layers=27)
Defensive patterns

Strategy: type-guard

Validate before calling

assert isinstance(encoder_outputs, (list, tuple)), type(encoder_outputs)

Type guard

def is_layer_list(x): return isinstance(x, (list, tuple)) and all(t.ndim == 3 for t in x)

Prevention

When it happens

Trigger: Passing a final-hidden-states tensor instead of the per-layer output list when select_layers is set — e.g. the vision encoder was run without output_hidden_states=True equivalent, or the last-element shortcut at the top of the function already collapsed the list.

Common situations: Custom vision-tower wrappers that reuse this helper but call the encoder in a mode returning only the last tensor; upstream signature changes after refactors.

Understand the failure class

Background: "Wrong argument type", "must be a string", "expected Array or Prism::Scope": TypeError and ArgumentError when a library receives a value of the wrong type — this error's family across 28 libraries.

Related errors


AI-assisted analysis of sgl-project/sglang@0132848349 (2026-08-28). Data as JSON: /api/errors/7731967103fad135. Report an issue: GitHub.