{"record":{"id":"4861a53545ab7944","repo":"bmad-code-org/BMAD-METHOD","slug":"missing-config-value-key","errorCode":null,"errorMessage":"missing config value `{key}`","messagePattern":"missing config value `(.+?)`","errorType":"exception","errorClass":"RenderError","httpStatus":null,"severity":"error","filePath":"src/scripts/render_skill.py","lineNumber":145,"sourceCode":"\ndef _find_config_values(data: Any, key: str, prefix: str = \"\") -> list[tuple[str, Any]]:\n    matches: list[tuple[str, Any]] = []\n    if not isinstance(data, dict):\n        return matches\n    for name, value in data.items():\n        path = f\"{prefix}.{name}\" if prefix else name\n        if name == key and not isinstance(value, (dict, list)):\n            matches.append((path, value))\n        matches.extend(_find_config_values(value, key, path))\n    return matches\n\n\ndef _resolve_short_config(\n    central: dict[str, Any], key: str, project_root: Path\n) -> tuple[str, str]:\n    matches = _find_config_values(central, key)\n    if not matches:\n        raise RenderError(f\"missing config value `{key}`\")\n    if len(matches) > 1:\n        paths = \", \".join(path for path, _ in matches)\n        raise RenderError(f\"ambiguous config value `{key}` found at: {paths}\")\n    path, value = matches[0]\n    return path, _resolve_config_value(value, f\"config.{path}\", project_root)\n\n\ndef _format_markdown_list(items: list[str]) -> str:\n    if not items:\n        return \"_None._\"\n    rendered = []\n    for item in items:\n        lines = item.splitlines() or [\"\"]\n        rendered.append(\"- \" + lines[0])\n        rendered.extend(\"  \" + line for line in lines[1:])\n    return \"\\n\".join(rendered)\n\n","sourceCodeStart":127,"sourceCodeEnd":163,"githubUrl":"https://github.com/bmad-code-org/BMAD-METHOD/blob/b70486b9bdcb0a404d329e2a763b57964e7f1360/src/scripts/render_skill.py#L127-L163","documentation":"Short-config tokens of the form {{.key}} are resolved by searching the entire central config tree for any field named key. If no field with that exact name exists anywhere in the merged central config (_bmad/config.toml plus user/custom layers), the renderer cannot resolve the token and aborts. This is distinct from the dotted {{config.a.b}} form which uses _lookup.","triggerScenarios":"A source contains {{.project_name}} but the merged central config has no key literally named project_name at any depth. _find_config_values returns an empty list, so _resolve_short_config raises.","commonSituations":"Typo in the token key; renamed config key; a missing config layer file; expecting a key from config.user.toml that was never created.","solutions":["Search central config for the key (grep -rn project_name _bmad/) and if absent, add it to _bmad/config.toml.","Correct the token spelling in the source to match an existing config key.","Switch to the explicit dotted form {{config.section.key}} for unambiguous resolution."],"exampleFix":"# before: source has {{.proj_name}} but config defines `name`\n# after (option A): fix the token\n{{.name}}\n# after (option B): add the key to _bmad/config.toml\n[project]\nproj_name = \"my-app\"","handlingStrategy":"validation","validationCode":"import re, tomllib\nfrom pathlib import Path\n\nSHORT = re.compile(r\"\\{\\{\\.([A-Za-z0-9_]+)\\}\\}\")\n\ndef collect_keys(obj) -> set[str]:\n    keys: set[str] = set()\n    if isinstance(obj, dict):\n        for k, v in obj.items():\n            keys.add(k); keys |= collect_keys(v)\n    return keys\n\ndef validate_short_tokens(sources: dict[str,str], central_path: Path) -> None:\n    central = tomllib.loads(Path(central_path).read_text(encoding=\"utf-8\"))\n    have = collect_keys(central)\n    for txt in sources.values():\n        for m in SHORT.finditer(txt):\n            if m.group(1) not in have:\n                raise SystemExit(f\"missing config value `{m.group(1)}`\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Grep central config for each {{.key}} token before rendering.","Prefer the explicit {{config.section.key}} form for clarity.","Keep a single source of truth for each short-config key."],"tags":["python","config","toml","token","validation"],"backgroundTag":null,"analyzedSha":"b70486b9bdcb0a404d329e2a763b57964e7f1360","analyzedAt":"2026-08-13T01:21:12.247Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}