vllm-project/vllm · error · ValueError
Cannot merge nested option {'.'.join(path)!r}: {part!r} is a
Error message
Cannot merge nested option {'.'.join(path)!r}: {part!r} is already a scalar What it means
merge_value() builds a nested dict from dotted CLI options (e.g. --quantization.pratio=0.5). While walking each path segment it requires that intermediate segments be dicts; if an earlier option already stored a scalar at that segment (or YAML alias collision), merging a nested key under it raises this ValueError.
Source
Thrown at tools/recipes/recipe_json_to_vllm_config.py:425
def is_option_token(token: str) -> bool:
if token.startswith("--"):
return True
if token in SHORT_ALIASES or token == "-O":
return True
return token.startswith("-O") and len(token) > 2
def merge_value(dst: dict[str, Any], path: list[str], value: Any) -> None:
"""Merge dotted CLI args into nested YAML dictionaries."""
cur = dst
for part in path[:-1]:
existing = cur.get(part)
if existing is None:
cur[part] = {}
elif not isinstance(existing, dict):
raise ValueError(
f"Cannot merge nested option {'.'.join(path)!r}: "
f"{part!r} is already a scalar"
)
cur = cur[part]
leaf = path[-1]
if leaf not in cur:
cur[leaf] = value
return
# Repeated CLI option. Preserve all values.
old = cur[leaf]
if not isinstance(old, list):
old = [old]
if isinstance(value, list):
old.extend(value)
else:
old.append(value)View on GitHub (pinned to c794754062)
Solutions
- Inspect the recipe's argv (jq '.argv' recipe.json) and find the two options sharing the dotted prefix
- Fix the source recipe: use the nested form consistently (--rope-scaling.rope-type plus --rope-scaling.factor) and drop the conflicting scalar form
- If the collision comes from normalization, rename one option in the recipe JSON or patch SHORT_ALIASES/normalize_key handling locally
- Report the offending argv to the Recipes maintainers if the recipe is server-rendered
Example fix
# before (conflicting scalar + nested forms in argv) ["vllm","serve","m","--rope-scaling","1.0","--rope-scaling.rope-type","linear"] # after (nested form only) ["vllm","serve","m","--rope-scaling.rope-type","linear","--rope-scaling.factor","8.0"]
Defensive patterns
Strategy: validation
Validate before calling
def check_no_prefix_collisions(argv: list[str]) -> None:
keys = set()
for t in argv:
if t.startswith("--") and "=" in t:
keys.add(t[2:].split("=", 1)[0])
for k in keys:
for other in keys:
if other != k and other.startswith(k + "."):
raise SystemExit(f"option prefix collision: {k} vs {other}") Type guard
def option_is_mergeable(existing: object) -> bool:
return existing is None or isinstance(existing, dict) Prevention
- Use one form per option: either the scalar flag or the dotted nested keys, never both
- When generating recipe argv programmatically, group dotted options under a single parent key
When it happens
Trigger: A recipe argv containing both a scalar option and a nested option sharing a prefix, e.g. `--rope-scaling 1.0` followed by `--rope-scaling.rope-type linear`, or two Recipes-rendered options whose normalized keys collide after underscore->dash normalization.
Common situations: Recipes API starts emitting compound/dotted options that overlap with existing flat flags; hand-edited recipe JSON with conflicting options; normalization (underscores to dashes in the top-level key) accidentally mapping two distinct keys onto the same path.
Related errors
- Expected recipe argv to start with: ['vllm', 'serve', MODEL,
- Expected model after 'vllm serve', got {model!r}
- -O is missing its value
- {token} is missing its value
- Unexpected positional/short argument {token!r}. The converte
AI-assisted analysis of vllm-project/vllm@c794754062 (2026-08-14).
Data as JSON: /api/errors/934fa29749fb2aff.
Report an issue: GitHub.