bmad-code-org/BMAD-METHOD · critical · RenderError
generation output hash mismatch: {destination / name}
Error message
generation output hash mismatch: {destination / name} What it means
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.
Source
Thrown at src/scripts/render_skill.py:292
except (OSError, UnicodeError, json.JSONDecodeError) as error:
raise RenderError(f"corrupt existing generation {destination}: {error}") from error
if existing != manifest:
raise RenderError(f"generation collision or corruption at {destination}")
expected_files = set(manifest["outputs"]) | {"manifest.json"}
actual_files = {
path.relative_to(destination).as_posix()
for path in destination.rglob("*")
if path.is_file()
}
if actual_files != expected_files:
raise RenderError(f"generation contains unexpected or missing files: {destination}")
for name, expected_hash in manifest["outputs"].items():
try:
actual_hash = _hash_bytes((destination / name).read_bytes())
except OSError as error:
raise RenderError(f"failed to verify {destination / name}: {error}") from error
if actual_hash != expected_hash:
raise RenderError(f"generation output hash mismatch: {destination / name}")
def _publish(destination: Path, outputs: dict[str, bytes], manifest: dict[str, Any]) -> None:
destination.parent.mkdir(parents=True, exist_ok=True)
if destination.exists():
_verify_existing(destination, manifest)
return
staging = Path(tempfile.mkdtemp(prefix=".staging-", dir=destination.parent))
try:
for name, content in outputs.items():
path = staging / name
path.parent.mkdir(parents=True, exist_ok=True)
path.write_bytes(content)
(staging / "manifest.json").write_bytes(
json.dumps(manifest, ensure_ascii=False, indent=2, sort_keys=True).encode("utf-8")
+ b"\n"
)
try:View on GitHub (pinned to b70486b9bd)
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.
Example fix
# before: hand-edited workflow.md changes its bytes # after rm -rf _bmad/render/<skill>/<slug>-<hash> python src/scripts/render_skill.py --project-root . --skill skills/my-skill
Defensive patterns
Strategy: try-catch
Validate before calling
import hashlib, json
from pathlib import Path
def verify_hashes(dest: Path) -> None:
manifest = json.loads((dest / "manifest.json").read_text(encoding="utf-8"))
for name, expected in manifest["outputs"].items():
actual = hashlib.sha256((dest / name).read_bytes()).hexdigest()
if actual != expected:
raise SystemExit(f"hash mismatch: {dest / name}") Try / catch
from render_skill import render, RenderError
try:
entry = render(project_root, skill_dir)
except RenderError as e:
if "output hash mismatch" in str(e):
# a generated file was tampered with -- delete the dir and regenerate
...
raise Prevention
- 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.
When it happens
Trigger: 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.
Common situations: Accidentally editing a rendered file; a tool rewriting line endings; VCS checkout on a different OS converting CRLF/LF.
Related errors
- generation collision or corruption at {destination}
- generation contains unexpected or missing files: {destinatio
- corrupt existing generation {destination}: {error}
- failed to verify {destination / name}: {error}
- {label} must be a list of tables
AI-assisted analysis of bmad-code-org/BMAD-METHOD@b70486b9bd (2026-08-13).
Data as JSON: /api/errors/4a733e12c442add7.
Report an issue: GitHub.