sgl-project/sglang · error · ValueError

Config file must contain a dictionary at root level

Error message

Config file must contain a dictionary at root level

What it means

YAML configs must be a mapping of option-name to value at the root. After yaml.safe_load, empty/None files become {}, but any other non-dict root (list, scalar, plain string) raises this error.

Source

Thrown at python/sglang/srt/utils/server_args_config_parser.py:128

        Raises:
            ValueError: If file is not YAML or cannot be read
        """
        self._validate_yaml_file(file_path)

        try:
            with open(file_path, "r") as file:
                config_data = yaml.safe_load(file)
        except Exception as e:
            logger.error(f"Failed to read config file {file_path}: {e}")
            raise

        # Handle empty files or None content
        if config_data is None:
            config_data = {}

        if not isinstance(config_data, dict):
            raise ValueError("Config file must contain a dictionary at root level")

        return config_data

    def _validate_yaml_file(self, file_path: str) -> None:
        """Validate that the file is a YAML file."""
        path = Path(file_path)
        if path.suffix.lower() not in [".yaml", ".yml"]:
            raise ValueError(f"Config file must be YAML format, got: {path.suffix}")

        if not path.exists():
            raise ValueError(f"Config file not found: {file_path}")

    def _convert_config_to_args(self, config: Dict[str, Any]) -> List[str]:
        """Convert configuration dictionary to argument list."""
        args = []

        for key, value in config.items():
            key_norm = key.replace("-", "_")

View on GitHub (pinned to 0132848349)

Solutions

  1. Make the root a mapping: top-level `key: value` lines with no leading dash
  2. Wrap the list under a named key if the list was intentional
  3. Validate with `python -c "import yaml;print(type(yaml.safe_load(open('cfg.yaml'))))` expecting dict

Example fix

# before
- model-path: meta-llama/Llama-3-8B
- port: 8000
# after
model-path: meta-llama/Llama-3-8B
port: 8000
Defensive patterns

Strategy: validation

Validate before calling

import yaml
data = yaml.safe_load(open("config.yaml"))
assert isinstance(data, dict) or data is None, "config root must be a mapping"

Type guard

def is_valid_config(data) -> bool:
    return data is None or isinstance(data, dict)

Prevention

When it happens

Trigger: A YAML file whose root node is a sequence (- model-path: x) or a bare scalar/string instead of key: value mappings.

Common situations: Hand-written config that indents all keys under a list dash, a JSON-style array file renamed to .yaml, or copy-pasting an example that used a list of configs.

Related errors


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