bmad-code-org/BMAD-METHOD · error · RenderError
render source is missing or not a file: {path}
Error message
render source is missing or not a file: {path} What it means
After confirming the resolved path is inside the skill dir, _load_sources checks path.is_file(). This fires when the path exists (resolve(strict=True) succeeded, so it is not missing) but is not a regular file -- typically a directory or a special file. rglob("*.md") can match a directory literally named something.md.
Source
Thrown at src/scripts/render_skill.py:108
),
}
if "when" in item:
layer["when"] = _require_string(item["when"], f"{item_label}.when")
result.append(layer)
return result
def _load_sources(skill_dir: Path) -> dict[str, str]:
sources: dict[str, str] = {}
for candidate in sorted(skill_dir.rglob("*.md")):
if candidate.name == "SKILL.md":
continue
name = candidate.relative_to(skill_dir).as_posix()
path = candidate.resolve(strict=True)
if not path.is_relative_to(skill_dir):
raise RenderError(f"render source escapes skill directory: {name}")
if not path.is_file():
raise RenderError(f"render source is missing or not a file: {path}")
try:
sources[name] = path.read_text(encoding="utf-8")
except (OSError, UnicodeError) as error:
raise RenderError(f"failed to read render source {path}: {error}") from error
if "workflow.md" not in sources:
raise RenderError(f"render entry is missing: {skill_dir / 'workflow.md'}")
return sources
def _resolve_config_value(value: Any, label: str, project_root: Path) -> str:
text = _require_string(value, label)
if "{project-root}" not in text:
return text
resolved = text.replace("{project-root}", str(project_root))
if not Path(resolved).is_absolute():
raise RenderError(f"{label} must resolve to an absolute path: {resolved}")
return resolved
View on GitHub (pinned to b70486b9bd)
Solutions
- Remove or rename the non-file entry matching *.md so all matches are regular files.
- Locate directory matches with: find <skill_dir> -name '*.md' -type d.
- Ensure no FIFO/socket/device files are named *.md in the skill tree.
Example fix
# before: a directory named changelog.md exists skills/my-skill/changelog.md/inner.md # after: rename the directory so it does not match *.md skills/my-skill/changelog/inner.md
Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
def assert_all_md_are_files(skill_dir: Path) -> None:
for cand in skill_dir.rglob("*.md"):
if cand.name == "SKILL.md":
continue
real = cand.resolve(strict=True)
if not real.is_file():
raise SystemExit(f"not a regular file: {real}") Prevention
- Do not name directories with a .md suffix.
- Check for directory matches: find <skill_dir> -name '*.md' -type d.
- Keep skill sources as plain regular files.
When it happens
Trigger: A directory named e.g. changelog.md inside the skill dir, or a FIFO/device file matching the *.md glob. resolve(strict=True) does not raise (the path exists), but is_file() is False.
Common situations: A directory accidentally named with a .md suffix; archive folders; special files on unusual filesystems.
Related errors
- render source escapes skill directory: {name}
- failed to read render source {path}: {error}
- render entry is missing: {skill_dir / 'workflow.md'}
- .memlog.md has no frontmatter
- .memlog.md frontmatter is not terminated
AI-assisted analysis of bmad-code-org/BMAD-METHOD@b70486b9bd (2026-08-13).
Data as JSON: /api/errors/c6ae5e5edf9f46b3.
Report an issue: GitHub.