sgl-project/sglang · error · ValueError

override_server_args: unknown ServerArgs field(s): {sorted(u

Error message

override_server_args: unknown ServerArgs field(s): {sorted(unknown)}

What it means

The override_server_args context manager validates that every non-underscore field it was given is a real ServerArgs dataclass field. Unknown names are rejected with this ValueError listing the sorted offending names. Underscore-prefixed names are exempt because they seed private property caches, not config fields.

Source

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

        self._prev_bags = ctx._config_bags
        self._prev_overrides_log = ctx._overrides_log
        self._prev_publish_role = ctx._publish_role
        self._prev_parallel_config = ctx.parallel._config
        self._prev_capture = ctx.flags.capture.enable_torch_compile
        from sglang.srt.arg_groups.overrides import (
            _apply_fields,
            declare_late_resolution,
        )

        server_args = ServerArgs(model_path="dummy")
        server_args.resolve_once()
        # Underscore names seed private property caches (the strict guard
        # exempts them); everything else must be a real config field.
        unknown = {name for name in self._fields if not name.startswith("_")} - set(
            type(server_args).__dataclass_fields__
        )
        if unknown:
            raise ValueError(
                f"override_server_args: unknown ServerArgs field(s): {sorted(unknown)}"
            )
        # Declared so the projection sees it; late, because the record is
        # resolved already and not yet published.
        # Underscore names are not fields at all (they seed private property
        # caches), so they stay a direct write.
        declared = {
            name: value for name, value in self._fields.items() if name[0] != "_"
        }
        if declared:
            declare_late_resolution(server_args, "override_server_args", **declared)
        # This hook stands in for a launch: the caller's values are both what
        # the operator passed and what resolution decided, so they go on the
        # record as well as into the stash. Production late resolution declares
        # only -- there the record stays the operator's input.
        _apply_fields(server_args, self._fields)
        ctx.set_server_args(server_args)
        self._installed = True

View on GitHub (pinned to 0132848349)

Solutions

  1. Use the exact ServerArgs dataclass field name (check ServerArgs.__dataclass_fields__)
  2. If the field was renamed upstream, update the call site to the new name
  3. Only use underscore-prefixed names if you intentionally seed a private property cache

Example fix

# before
with ctx.override_server_args(tp_size=4):
    ...
# after
with ctx.override_server_args(tensor_parallel_size=4):
    ...
Defensive patterns

Strategy: validation

Validate before calling

from dataclasses import fields
from sglang.srt.server_args import ServerArgs
valid = {f.name for f in fields(ServerArgs)}
unknown = {k for k in overrides if not k.startswith("_")} - valid
if unknown:
    raise ValueError(f"bad override keys: {sorted(unknown)}")
with ctx.override_server_args(**overrides):
    ...

Prevention

When it happens

Trigger: with ctx.override_server_args(tp_size=4): where 'tp_size' is not a ServerArgs field (real name is tensor_parallel_size); passing an obsolete field name after an upgrade renamed it; passing arbitrary kwargs the API does not accept.

Common situations: Typos or outdated field names in tests or override call sites after ServerArgs fields were renamed; copy-pasting kwargs from a different CLI/config schema into the override.

Related errors


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