sgl-project/sglang · error · ValueError

{name!r} is not a config leaf (no NS namespace)

Error message

{name!r} is not a config leaf (no NS namespace)

What it means

config_leaf resolves the field name via namespace_of(ServerArgs), which maps each dataclass field to its namespaced config path. If the field has no NS namespace mapping (it is not a published config leaf), the lookup returns None and this ValueError is raised. It means the name you asked for is either misspelled or is not part of the namespaced config surface.

Source

Thrown at python/sglang/srt/runtime_context.py:938

        for bag, name, value in targets:
            bag._set(name, value)
        self._overrides_log.append((source, dict(fields)))

    def config_leaf(self, name: str):
        """One resolved config leaf by field name — the read side of ``override``.

        Callers that hold a field name rather than a namespace (a readback
        endpoint, a control-plane handler) would otherwise have to know which
        bag it lives in.
        """
        bags = self._config_bags
        if bags is None:
            raise ValueError("config not published; cannot read a config leaf")
        from sglang.srt.arg_groups.arg_utils import namespace_of

        path = namespace_of(type(self._server_args)).get(name)
        if path is None:
            raise ValueError(f"{name!r} is not a config leaf (no NS namespace)")
        parts = path.split(".")
        bag = self.config_bag(parts[0])
        for seg in parts[1:]:
            bag = object.__getattribute__(bag, "_subs").get(seg)
            if bag is None:
                raise ValueError(f"subgroup {seg!r} missing under {path!r}")
        return getattr(bag, name)

    def overrides_log(self) -> list:
        """Provenance of post-publish ``override`` calls: ``[(source, {field: value})]``.

        Returns deep-ish copies (source, dict(fields)) so callers inspecting the
        log cannot mutate the recorded provenance in place."""
        return [(source, dict(fields)) for source, fields in self._overrides_log]

    def resolved_server_args_dict(self, base: dict | None = None) -> dict:
        """Serialize the *resolved* config: the pristine ``server_args`` fields
        with every post-publish ``override`` overlaid.

View on GitHub (pinned to 0132848349)

Solutions

  1. Check namespace_of(ServerArgs).keys() for the exact published field name and use it
  2. Verify the field still exists on ServerArgs (typo or renamed field)
  3. If the value genuinely is not a config leaf, read it from the ServerArgs object directly rather than config_leaf

Example fix

# before
value = ctx.config_leaf("tp_size")
# after
from sglang.srt.arg_groups.arg_utils import namespace_of
from sglang.srt.server_args import ServerArgs
assert "tensor_parallel_size" in namespace_of(ServerArgs)
value = ctx.config_leaf("tensor_parallel_size")
Defensive patterns

Strategy: validation

Validate before calling

from sglang.srt.arg_groups.arg_utils import namespace_of
from sglang.srt.server_args import ServerArgs
if name not in namespace_of(ServerArgs):
    raise KeyError(f"{name} is not a config leaf")
value = ctx.config_leaf(name)

Type guard

def is_config_leaf(name: str) -> bool:
    from sglang.srt.arg_groups.arg_utils import namespace_of
    from sglang.srt.server_args import ServerArgs
    return name in namespace_of(ServerArgs)

Prevention

When it happens

Trigger: Calling ctx.config_leaf("tp_size") when the actual ServerArgs field is named differently (e.g. tensor_parallel_size), asking for a ServerArgs field deliberately excluded from the NS namespace mapping, or passing a plain non-field attribute name.

Common situations: Typos in readback/control-plane endpoints that take a field name from a request; fields renamed across a version upgrade so the old name is no longer a config leaf; passing a private attribute or cache name.

Related errors


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