bmad-code-org/BMAD-METHOD · error · RenderError
ambiguous config value `{key}` found at: {paths}
Error message
ambiguous config value `{key}` found at: {paths} What it means
The short-config resolver requires exactly one match for {{.key}} across the whole central config tree. If the same terminal key name appears in multiple sections (e.g. project.name and team.name), it cannot choose deterministically and aborts, listing every location found.
Source
Thrown at src/scripts/render_skill.py:148
if not isinstance(data, dict):
return matches
for name, value in data.items():
path = f"{prefix}.{name}" if prefix else name
if name == key and not isinstance(value, (dict, list)):
matches.append((path, value))
matches.extend(_find_config_values(value, key, path))
return matches
def _resolve_short_config(
central: dict[str, Any], key: str, project_root: Path
) -> tuple[str, str]:
matches = _find_config_values(central, key)
if not matches:
raise RenderError(f"missing config value `{key}`")
if len(matches) > 1:
paths = ", ".join(path for path, _ in matches)
raise RenderError(f"ambiguous config value `{key}` found at: {paths}")
path, value = matches[0]
return path, _resolve_config_value(value, f"config.{path}", project_root)
def _format_markdown_list(items: list[str]) -> str:
if not items:
return "_None._"
rendered = []
for item in items:
lines = item.splitlines() or [""]
rendered.append("- " + lines[0])
rendered.extend(" " + line for line in lines[1:])
return "\n".join(rendered)
def _format_review_layers(layers: list[dict[str, str]]) -> str:
active = [layer for layer in layers if layer["instruction"].strip()]
if not active:View on GitHub (pinned to b70486b9bd)
Solutions
- Switch the token to the explicit dotted form {{config.section.name}}.
- Rename one of the colliding keys so only one match remains.
- Use the full dotted paths reported in {paths} to disambiguate.
Example fix
# before: {{.name}} is ambiguous between project.name and team.name
# after: use the explicit path
{{config.project.name}} Defensive patterns
Strategy: validation
Validate before calling
import re, tomllib
from pathlib import Path
SHORT = re.compile(r"\{\{\.([A-Za-z0-9_]+)\}\}")
def find_keys(obj, prefix="") -> list[str]:
out: list[str] = []
if isinstance(obj, dict):
for k, v in obj.items():
path = f"{prefix}.{k}" if prefix else k
if not isinstance(v, (dict, list)):
out.append(path)
out += find_keys(v, path)
return out
def validate_short_tokens_unambiguous(sources: dict[str,str], central_path: Path) -> None:
central = tomllib.loads(Path(central_path).read_text(encoding="utf-8"))
all_paths = find_keys(central)
for txt in sources.values():
for m in SHORT.finditer(txt):
key = m.group(1)
hits = [p for p in all_paths if p.split(".")[-1] == key]
if len(hits) > 1:
raise SystemExit(f"ambiguous {key}: {hits}") Prevention
- Avoid reusing common leaf names (name, id, version) across sections when using short tokens.
- Switch ambiguous tokens to the dotted {{config.section.key}} form.
- Lint for duplicate terminal keys in central config.
When it happens
Trigger: Source uses {{.name}}; central config contains both [project] name=... and [team] name=... . _find_config_values returns two matches, so _resolve_short_config raises with the dotted paths joined by commas.
Common situations: Reusing common key names (name, id, version, path) across multiple TOML sections; merging several config layers that each define a same-named leaf.
Related errors
- missing config value `{key}`
- {label} must resolve to an absolute path: {resolved}
- keyed array identifier `{candidate}` must not be empty
- {label} must be a list of tables
- {item_label} must be a table
AI-assisted analysis of bmad-code-org/BMAD-METHOD@b70486b9bd (2026-08-13).
Data as JSON: /api/errors/687a9b97a92f32dd.
Report an issue: GitHub.