{"record":{"id":"4a733e12c442add7","repo":"bmad-code-org/BMAD-METHOD","slug":"generation-output-hash-mismatch-destination-na","errorCode":null,"errorMessage":"generation output hash mismatch: {destination / name}","messagePattern":"generation output hash mismatch: (.+?)","errorType":"exception","errorClass":"RenderError","httpStatus":null,"severity":"critical","filePath":"src/scripts/render_skill.py","lineNumber":292,"sourceCode":"    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\"}\n    actual_files = {\n        path.relative_to(destination).as_posix()\n        for path in destination.rglob(\"*\")\n        if path.is_file()\n    }\n    if actual_files != expected_files:\n        raise RenderError(f\"generation contains unexpected or missing files: {destination}\")\n    for name, expected_hash in manifest[\"outputs\"].items():\n        try:\n            actual_hash = _hash_bytes((destination / name).read_bytes())\n        except OSError as error:\n            raise RenderError(f\"failed to verify {destination / name}: {error}\") from error\n        if actual_hash != expected_hash:\n            raise RenderError(f\"generation output hash mismatch: {destination / name}\")\n\n\ndef _publish(destination: Path, outputs: dict[str, bytes], manifest: dict[str, Any]) -> None:\n    destination.parent.mkdir(parents=True, exist_ok=True)\n    if destination.exists():\n        _verify_existing(destination, manifest)\n        return\n    staging = Path(tempfile.mkdtemp(prefix=\".staging-\", dir=destination.parent))\n    try:\n        for name, content in outputs.items():\n            path = staging / name\n            path.parent.mkdir(parents=True, exist_ok=True)\n            path.write_bytes(content)\n        (staging / \"manifest.json\").write_bytes(\n            json.dumps(manifest, ensure_ascii=False, indent=2, sort_keys=True).encode(\"utf-8\")\n            + b\"\\n\"\n        )\n        try:","sourceCodeStart":274,"sourceCodeEnd":310,"githubUrl":"https://github.com/bmad-code-org/BMAD-METHOD/blob/b70486b9bdcb0a404d329e2a763b57964e7f1360/src/scripts/render_skill.py#L274-L310","documentation":"The SHA-256 of an existing output file does not match the hash recorded in manifest.json. The file's content was altered after generation, breaking the immutability guarantee, so the renderer refuses to proceed rather than silently accept tampered output.","triggerScenarios":"A file under an existing generation directory was edited by hand (or rewritten by a formatter/linter) so its bytes no longer match the manifest hash.","commonSituations":"Accidentally editing a rendered file; a tool rewriting line endings; VCS checkout on a different OS converting CRLF/LF.","solutions":["Delete the modified generation directory and re-render to regenerate correct hashes.","Prevent formatters/linters/editors from touching generated dirs (add to ignore lists).","Normalize line endings via .gitattributes (* text=auto eol=lf) for cross-platform consistency."],"exampleFix":"# before: hand-edited workflow.md changes its bytes\n# after\nrm -rf _bmad/render/<skill>/<slug>-<hash>\npython src/scripts/render_skill.py --project-root . --skill skills/my-skill","handlingStrategy":"try-catch","validationCode":"import hashlib, json\nfrom pathlib import Path\n\ndef verify_hashes(dest: Path) -> None:\n    manifest = json.loads((dest / \"manifest.json\").read_text(encoding=\"utf-8\"))\n    for name, expected in manifest[\"outputs\"].items():\n        actual = hashlib.sha256((dest / name).read_bytes()).hexdigest()\n        if actual != expected:\n            raise SystemExit(f\"hash mismatch: {dest / name}\")","typeGuard":null,"tryCatchPattern":"from render_skill import render, RenderError\n\ntry:\n    entry = render(project_root, skill_dir)\nexcept RenderError as e:\n    if \"output hash mismatch\" in str(e):\n        # a generated file was tampered with -- delete the dir and regenerate\n        ...\n    raise","preventionTips":["Treat generated output as read-only.","Add *.gitattributes* rules (* text=auto eol=lf) to stop line-ending rewrites.","Keep formatters/linters away from generation directories."],"tags":["python","manifest","integrity","hash","idempotency","tampering"],"backgroundTag":null,"analyzedSha":"b70486b9bdcb0a404d329e2a763b57964e7f1360","analyzedAt":"2026-08-13T01:21:12.247Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}