calesthio/OpenMontage · error · FileNotFoundError
Playbook not found: {path}
Error message
Playbook not found: {path} What it means
FileNotFoundError raised by load_playbook when the requested style playbook YAML (<name>.yaml) does not exist under STYLES_DIR (or the styles_dir override). It is a plain existence check before yaml.safe_load, so the file was never opened — the failure is purely path/name resolution, not YAML parsing or schema validation.
Source
Thrown at styles/playbook_loader.py:46
def _load_playbook_schema() -> dict:
with open(SCHEMA_PATH, encoding="utf-8") as f:
return json.load(f)
def load_playbook(name: str, styles_dir: Optional[Path] = None) -> dict[str, Any]:
"""Load and validate a style playbook by name.
Args:
name: Playbook name (without .yaml extension).
styles_dir: Override directory for playbook files.
Returns:
Validated playbook dict.
"""
styles_dir = styles_dir or STYLES_DIR
path = styles_dir / f"{name}.yaml"
if not path.exists():
raise FileNotFoundError(f"Playbook not found: {path}")
with open(path, encoding="utf-8") as f:
playbook = yaml.safe_load(f)
validate_playbook(playbook)
return playbook
def validate_playbook(playbook: dict) -> None:
"""Validate a playbook dict against the schema."""
schema = _load_playbook_schema()
jsonschema.validate(instance=playbook, schema=schema)
def list_playbooks(styles_dir: Optional[Path] = None) -> list[str]:
"""List all available playbook names."""
styles_dir = styles_dir or STYLES_DIR
return [View on GitHub (pinned to 95e1c3d0ab)
Solutions
- List the styles directory (or call the registry/API that enumerates playbooks) and use an exact existing name
- If a custom playbook is intended, place <name>.yaml in styles_dir and ensure it passes validate_playbook
- Pass the name without the .yaml extension — the loader appends it
- For custom locations, pass styles_dir explicitly as an absolute Path
Example fix
# before
playbook = load_playbook("corparate-modern") # typo
# after
from pathlib import Path
playbook = load_playbook("corporate-modern", styles_dir=Path("/abs/styles")) Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
def playbook_path(styles_dir: Path, name: str) -> Path:
clean = name.removesuffix(".yaml").removesuffix(".yml")
return styles_dir / f"{clean}.yaml"
p = playbook_path(STYLES_DIR, name)
if not p.exists():
available = sorted(x.stem for x in STYLES_DIR.glob("*.yaml"))
raise SystemExit(f"unknown playbook {name!r}; available: {available}") Type guard
def playbook_exists(name: str, styles_dir: Path | None = None) -> bool:
d = styles_dir or STYLES_DIR
return (d / f"{name.removesuffix('.yaml')}.yaml").is_file() Try / catch
try:
playbook = load_playbook(name)
except FileNotFoundError:
raise SystemExit(f"playbook {name!r} not found — check styles/ for valid names") Prevention
- Enumerate available playbooks from styles/*.yaml and expose them in UX instead of free-text input
- Strip .yaml suffixes from user input before loading
- Use absolute styles_dir overrides for custom locations
When it happens
Trigger: Calling load_playbook(name) with a typo'd or nonexistent playbook name; pointing styles_dir at a custom directory that lacks the file; case-sensitivity mismatch of the name on Linux; referencing a playbook that was renamed or deleted from styles/.
Common situations: Docs reference a playbook removed in a refactor; user copies a config referencing a company playbook not shipped with the repo; running from a different working directory where a relative styles_dir override resolves incorrectly; name given with the .yaml extension included producing name.yaml.yaml.
Related errors
- Playbook not found: {name}
- media not found
- Invalid stage: {stage!r} for pipeline {pipeline_type!r}. Val
- Pipeline manifest not found: {path}
- Error: No demo prop files were found in {PROPS_DIR}.
AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15).
Data as JSON: /api/errors/4fedb0c6e61bff8f.
Report an issue: GitHub.