{"record":{"id":"6608e28f44d0c571","repo":"calesthio/OpenMontage","slug":"error-path-must-define-at-least-one-cut","errorCode":null,"errorMessage":"Error: {path} must define at least one cut.","messagePattern":"Error: (.+?) must define at least one cut\\.","errorType":"console","errorClass":"SystemExit","httpStatus":null,"severity":"error","filePath":"render_demo.py","lineNumber":73,"sourceCode":"        raise SystemExit(\"Error: npm is required but was not found on PATH.\")\n\n    npx_cmd = find_command(\"npx.cmd\", \"npx\", \"npx.exe\")\n    if not npx_cmd:\n        raise SystemExit(\"Error: npx is required but was not found on PATH.\")\n\n    if not (COMPOSER_DIR / \"node_modules\").exists():\n        print(\"Installing Remotion dependencies...\")\n        subprocess.run([npm_cmd, \"install\"], cwd=COMPOSER_DIR, check=True)\n\n    return npx_cmd\n\n\ndef validate_props_file(path: Path) -> None:\n    with path.open(\"r\", encoding=\"utf-8\") as handle:\n        payload = json.load(handle)\n\n    if not isinstance(payload.get(\"cuts\"), list) or not payload[\"cuts\"]:\n        raise SystemExit(f\"Error: {path} must define at least one cut.\")\n\n\ndef render_demo(name: str, props_path: Path, npx_cmd: str) -> None:\n    validate_props_file(props_path)\n    OUTPUT_DIR.mkdir(parents=True, exist_ok=True)\n    output_path = OUTPUT_DIR / f\"{name}.mp4\"\n\n    print()\n    print(f\"Rendering: {name}\")\n    print(f\"Props:     {props_path}\")\n    print(f\"Output:    {output_path}\")\n    print()\n\n    subprocess.run(\n        [\n            npx_cmd,\n            \"remotion\",\n            \"render\",","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/render_demo.py#L55-L91","documentation":"Raised by render_demo.py's validate_props_file() as SystemExit when the demo props JSON loads successfully but its 'cuts' key is missing, not a list, or an empty list. The Remotion demo composition is driven entirely by the checked-in props file's cuts array; with zero cuts there is nothing to render, so the script aborts before invoking npx. This is a props-shape check: a plain JSON parse error would surface differently (from json.load), while this error is specifically about the cuts field.","triggerScenarios":"Passing a hand-written or edited props file whose top-level 'cuts' array was deleted, renamed (e.g. 'scenes'), or left empty; passing a props file from a different tool whose schema doesn't use cuts; a truncating edit that dropped the closing entries.","commonSituations":"Authoring a new demo by copying and trimming an existing props file down to nothing; schema drift after the composition changed its props shape; JSON with cuts: null.","solutions":["Open the props file and ensure it has a top-level \"cuts\": [ ... ] array with at least one cut object.","Compare against a working checked-in demo in PROPS_DIR and mirror its structure.","If you renamed or restructured the field, rename it back to cuts."],"exampleFix":"// props.json — before\n{ \"scenes\": [{ \"start\": 0 }] }\n\n// props.json — after\n{ \"cuts\": [{ \"start\": 0, \"end\": 5, \"label\": \"intro\" }] }","handlingStrategy":"validation","validationCode":"import json\n\ndef props_are_renderable(path) -> bool:\n    with open(path) as f:\n        payload = json.load(f)\n    cuts = payload.get(\"cuts\")\n    return isinstance(cuts, list) and len(cuts) > 0","typeGuard":"from typing import Any\n\ndef has_valid_cuts(payload: dict[str, Any]) -> bool:\n    cuts = payload.get(\"cuts\")\n    return isinstance(cuts, list) and bool(cuts) and all(isinstance(c, dict) for c in cuts)","tryCatchPattern":null,"preventionTips":["Validate the props shape (non-empty cuts list) right after authoring or editing.","Start new demo props by copying a working checked-in file.","Keep the field named exactly 'cuts' at the top level."],"tags":["props","validation","rendering","remotion"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}