calesthio/OpenMontage · error · FileNotFoundError
Playbook not found: {name}
Error message
Playbook not found: {name} What it means
Raised by lib/playbook_generator.py's load_existing_playbook() when no {name}.yaml exists in either the built-in styles directory (STYLES_DIR) or the custom styles directory (CUSTOM_STYLES_DIR). Playbooks are resolved by name with a .yaml extension appended, checked against the preset directory first, then the custom directory. list_playbooks() returns the exact valid names (preset + custom, deduplicated and sorted).
Source
Thrown at lib/playbook_generator.py:39
/ "schemas" / "styles" / "playbook.schema.json"
)
STYLES_DIR = Path(__file__).resolve().parent.parent / "styles"
CUSTOM_STYLES_DIR = STYLES_DIR / "custom"
def _load_playbook_schema() -> dict:
with open(PLAYBOOK_SCHEMA_PATH) as f:
return json.load(f)
def load_existing_playbook(name: str) -> dict[str, Any]:
"""Load an existing playbook YAML by name."""
path = STYLES_DIR / f"{name}.yaml"
if not path.exists():
# Check custom directory
path = CUSTOM_STYLES_DIR / f"{name}.yaml"
if not path.exists():
raise FileNotFoundError(f"Playbook not found: {name}")
with open(path) as f:
return yaml.safe_load(f)
def list_playbooks() -> list[str]:
"""List all available playbook names (preset + custom)."""
names = [p.stem for p in STYLES_DIR.glob("*.yaml")]
if CUSTOM_STYLES_DIR.exists():
names.extend(p.stem for p in CUSTOM_STYLES_DIR.glob("*.yaml"))
return sorted(set(names))
def generate_playbook(
name: str,
context: dict[str, Any],
base_playbook: str | None = None,
) -> dict[str, Any]:
"""Generate a custom playbook from production context.View on GitHub (pinned to 95e1c3d0ab)
Solutions
- Call list_playbooks() and copy the exact name (without extension).
- If it's a custom playbook, confirm the YAML file sits in CUSTOM_STYLES_DIR and the name matches including case.
- Pass the bare name without the .yaml extension.
Example fix
# before
pb = load_existing_playbook("Cinematic.yaml") # FileNotFoundError
# after
from lib.playbook_generator import list_playbooks, load_existing_playbook
print(list_playbooks())
pb = load_existing_playbook("cinematic") Defensive patterns
Strategy: validation
Validate before calling
from lib.playbook_generator import list_playbooks
available = set(list_playbooks())
if playbook_name not in available:
raise SystemExit(f"Unknown playbook {playbook_name!r}. Available: {sorted(available)}") Type guard
from lib.playbook_generator import list_playbooks
def playbook_exists(name: str) -> bool:
return name in set(list_playbooks()) Try / catch
try:
playbook = load_existing_playbook(name)
except FileNotFoundError as e:
raise SystemExit(f"{e}. Run list_playbooks() to see valid names.") from e Prevention
- Use bare names without the .yaml extension.
- Place custom playbooks in CUSTOM_STYLES_DIR, not arbitrary folders.
- Names are case-sensitive; match the file stem exactly.
When it happens
Trigger: Calling load_existing_playbook with a typo'd name, wrong case, or a name that includes the .yaml suffix (making it look for name.yaml.yaml); referencing a custom playbook whose YAML was moved or never created in CUSTOM_STYLES_DIR.
Common situations: Typo in a config or CLI reference; custom playbook file saved in the wrong directory; playbook renamed between versions; case-sensitive mismatch on case-sensitive filesystems.
Related errors
- Pipeline manifest not found: {path}
- Playbook not found: {path}
- media not found
- Invalid stage: {stage!r} for pipeline {pipeline_type!r}. Val
- Required environment variable {key!r} is not set
AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15).
Data as JSON: /api/errors/8f09b093de46c792.
Report an issue: GitHub.