sgl-project/sglang · error · ValueError

layer_types has {len(self.layer_types)} entries but num_hidd

Error message

layer_types has {len(self.layer_types)} entries but num_hidden_layers is {self.num_hidden_layers}

What it means

When layer_types is explicitly provided it must have exactly num_hidden_layers entries, one per transformer layer. The validator only derives layer_types from no_rope_layers when it is None; otherwise the length is checked against num_hidden_layers and this error fires on mismatch.

Source

Thrown at python/sglang/srt/hardware_backend/mlx/models/muse_glimmer_mlx.py:297

                    f"num_hidden_layers is {self.num_hidden_layers}"
                )
            bad_flags = sorted(set(self.no_rope_layers) - {0, 1})
            if bad_flags:
                raise ValueError(
                    f"no_rope_layers contains non-binary entries {bad_flags}; "
                    "each entry must be 0 (NoPE) or 1 (RoPE)"
                )

        # NoPE layers are the full-attention layers; the rest slide.
        derived_layer_types = [
            "full_attention" if rope_flag == 0 else "sliding_attention"
            for rope_flag in self.no_rope_layers
        ]
        if self.layer_types is None:
            self.layer_types = derived_layer_types
        else:
            if len(self.layer_types) != self.num_hidden_layers:
                raise ValueError(
                    f"layer_types has {len(self.layer_types)} entries but "
                    f"num_hidden_layers is {self.num_hidden_layers}"
                )
            bad = sorted(
                set(self.layer_types) - {"full_attention", "sliding_attention"}
            )
            if bad:
                raise ValueError(
                    f"layer_types contains unknown entries {bad}; expected only "
                    "'full_attention' or 'sliding_attention'"
                )
            if self.layer_types != derived_layer_types:
                mismatches = [
                    i
                    for i, (got, want) in enumerate(
                        zip(self.layer_types, derived_layer_types)
                    )
                    if got != want

View on GitHub (pinned to 0132848349)

Solutions

  1. Either omit layer_types so it is derived from no_rope_layers
  2. Or pad/trim layer_types so len == num_hidden_layers
  3. Verify num_hidden_layers matches the actual checkpoint depth before loading

Example fix

// before (num_hidden_layers=24, but only 12 entries)
"layer_types": ["full_attention", "sliding_attention", ...12 total]
// after
"layer_types": null  // derived from no_rope_layers
Defensive patterns

Strategy: validation

Validate before calling

assert cfg.get("layer_types") is None or len(cfg["layer_types"]) == cfg["num_hidden_layers"]

Type guard

def layer_types_len_ok(cfg: dict) -> bool:
    lt = cfg.get("layer_types")
    return lt is None or (isinstance(lt, list) and len(lt) == cfg["num_hidden_layers"])

Prevention

When it happens

Trigger: Passing a layer_types list whose len differs from num_hidden_layers — e.g. truncating the list, adding an entry, or using a layer_types array copied from a model with a different layer count.

Common situations: Copying config.json between model variants (7B vs 3B with different depths), editing num_hidden_layers without updating layer_types, or partial manual merges of configs.

Related errors


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