{"record":{"id":"24a63d00ebc295a0","repo":"bmad-code-org/BMAD-METHOD","slug":"snapshot-reference-targets-undeclared-source-tar","errorCode":null,"errorMessage":"snapshot reference targets undeclared source: {target}","messagePattern":"snapshot reference targets undeclared source: (.+?)","errorType":"exception","errorClass":"RenderError","httpStatus":null,"severity":"error","filePath":"src/scripts/render_skill.py","lineNumber":260,"sourceCode":"        for token, value in replacements.items()\n    }\n    source_names = set(sources)\n    patterns = [\n        *(re.escape(token) for token in sorted(replacements, key=len, reverse=True)),\n        _SNAPSHOT_TOKEN.pattern,\n    ]\n    token_pattern = re.compile(\"|\".join(patterns))\n\n    def replace(match: re.Match[str]) -> str:\n        token = match.group(0)\n        if token in replacements:\n            return replacements[token]\n        snapshot = _SNAPSHOT_TOKEN.fullmatch(token)\n        if snapshot is None:\n            raise RenderError(f\"unsupported render token: {token}\")\n        target = snapshot.group(1)\n        if target not in source_names:\n            raise RenderError(f\"snapshot reference targets undeclared source: {target}\")\n        return str(destination / target)\n\n    rendered: dict[str, str] = {}\n    for name, content in sources.items():\n        # Inserted paths and customization prose are never scanned as source tokens.\n        rendered[name] = token_pattern.sub(replace, content)\n    return rendered\n\n\ndef _verify_existing(destination: Path, manifest: dict[str, Any]) -> None:\n    manifest_path = destination / \"manifest.json\"\n    try:\n        existing = json.loads(manifest_path.read_text(encoding=\"utf-8\"))\n    except (OSError, UnicodeError, json.JSONDecodeError) as error:\n        raise RenderError(f\"corrupt existing generation {destination}: {error}\") from error\n    if existing != manifest:\n        raise RenderError(f\"generation collision or corruption at {destination}\")\n    expected_files = set(manifest[\"outputs\"]) | {\"manifest.json\"}","sourceCodeStart":242,"sourceCodeEnd":278,"githubUrl":"https://github.com/bmad-code-org/BMAD-METHOD/blob/b70486b9bdcb0a404d329e2a763b57964e7f1360/src/scripts/render_skill.py#L242-L278","documentation":"Tokens of the form [[bmad-snapshot:foo.md]] resolve to the absolute destination path of another rendered source file. The target must be one of the collected source files. If foo.md is not a real source (typo, missing file, wrong case, or path outside the skill dir), the renderer refuses to emit a dangling reference.","triggerScenarios":"A source contains [[bmad-snapshot:glossary.md]] but the skill directory has no glossary.md (only Glossary.md, or it was deleted, or the relative path is wrong). target not in source_names.","commonSituations":"Renaming a referenced file without updating snapshot tokens; case mismatch; pointing to a non-.md file or to a file outside the skill directory.","solutions":["Create the referenced .md file in the skill directory, or correct the token to match an existing source name.","Check exact case and relative path (POSIX separators, relative to the skill root).","Remove the snapshot token if the reference is no longer needed."],"exampleFix":"# before: [[bmad-snapshot:Glossery.md]]  (typo, wrong case)\n# after\n[[bmad-snapshot:glossary.md]]","handlingStrategy":"validation","validationCode":"import re\nfrom pathlib import Path\n\nSNAP = re.compile(r\"\\[\\[bmad-snapshot:([A-Za-z0-9_./-]+\\.md)\\]\\]\")\n\ndef validate_snapshot_targets(skill_dir: Path) -> None:\n    sources = {p.relative_to(skill_dir).as_posix() for p in skill_dir.rglob(\"*.md\") if p.name != \"SKILL.md\"}\n    for md in skill_dir.rglob(\"*.md\"):\n        if md.name == \"SKILL.md\":\n            continue\n        for m in SNAP.finditer(md.read_text(encoding=\"utf-8\")):\n            if m.group(1) not in sources:\n                raise SystemExit(f\"snapshot target missing: {m.group(1)}\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep snapshot targets in sync with source filenames (update tokens when renaming).","Use exact case and POSIX relative paths in [[bmad-snapshot:...]] tokens.","Add a pre-render lint for dangling snapshot references."],"tags":["python","rendering","snapshot","validation","token"],"backgroundTag":null,"analyzedSha":"b70486b9bdcb0a404d329e2a763b57964e7f1360","analyzedAt":"2026-08-13T01:21:12.247Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}