sgl-project/sglang · error · ValueError

publish role {role!r} has no ROLE_NAMESPACE_SETS entry; decl

Error message

publish role {role!r} has no ROLE_NAMESPACE_SETS entry; declare its namespace set (None for the full tree).

What it means

When SGLANG_ROLE_NAMESPACES=enforce, publish(server_args, role=...) requires the role to have an entry in ROLE_NAMESPACE_SETS (which may be None for the full tree). Publishing with an undeclared role fails immediately at publish time — fail closed — rather than letting stray reads escape later.

Source

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

def publish(server_args, *, role: str, hf_config: Any = None) -> RuntimeContext:
    """Install process-wide config for this OS process.

    Records the process ``role`` — one of the ``ROLE_NAMESPACE_SETS`` keys,
    which is the one place the roles are enumerated — and
    projects the config bags. Draft workers skip publish (they must not clobber
    the target). ``role`` is provenance, and — when ``SGLANG_ROLE_NAMESPACES``
    is ``enforce`` — the key into ``ROLE_NAMESPACE_SETS`` for fail-closed
    namespace-read enforcement (``record`` audits the reads instead).
    ``hf_config`` is accepted for forward-compat and currently unused.

    A process holds at most one live config: the bags always describe the
    engine running now. Re-publish is allowed and is **last-publish-wins**
    (bags re-projected, provenance reset, role overwritten), which is what
    lets one process rebuild an engine after shutting the previous one down.
    """
    if _ROLE_NS_MODE == "enforce" and role not in ROLE_NAMESPACE_SETS:
        # Fail closed at publish time, not at the first stray read.
        raise ValueError(
            f"publish role {role!r} has no ROLE_NAMESPACE_SETS entry; declare "
            "its namespace set (None for the full tree)."
        )
    server_args.resolve_once()
    discarded = _CONTEXT.overrides_log()
    _CONTEXT.set_server_args(server_args)
    if discarded:
        logger.warning(
            "publish(role=%s) re-projected the config bags and dropped %d "
            "override(s) taken since the last publish: %s",
            role,
            len(discarded),
            ", ".join(
                f"{source}({', '.join(sorted(fields))})" for source, fields in discarded
            ),
        )
    _CONTEXT._publish_role = role
    if _ROLE_NS_MODE == "record":

View on GitHub (pinned to 0132848349)

Solutions

  1. Add an entry for the role in ROLE_NAMESPACE_SETS: an explicit namespace set, or None for the full tree
  2. Re-check the role string for typos against existing entries
  3. Use SGLANG_ROLE_NAMESPACES=record first to discover which namespaces the role touches, then declare the set and switch to enforce

Example fix

# before
ROLE_NAMESPACE_SETS = {"scheduler": {...}}
publish(args, role="detokenizer")  # enforce mode -> ValueError
# after
ROLE_NAMESPACE_SETS = {"scheduler": {...}, "detokenizer": None}
publish(args, role="detokenizer")
Defensive patterns

Strategy: validation

Validate before calling

from sglang.srt.runtime_context import ROLE_NAMESPACE_SETS
if role not in ROLE_NAMESPACE_SETS:
    raise ValueError(f"declare {role!r} in ROLE_NAMESPACE_SETS before publish under enforce")
publish(server_args, role=role)

Prevention

When it happens

Trigger: Calling publish(server_args, role="my_new_role") while SGLANG_ROLE_NAMESPACES=enforce and 'my_new_role' has no ROLE_NAMESPACE_SETS entry; adding a new process role (e.g. a new worker type) without declaring its namespace set.

Common situations: Introducing a new entry-point role in a fork/extension of sglang; flipping the env from record to enforce and discovering roles that were never declared; tests publishing under an ad-hoc role name.

Related errors


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