{"record":{"id":"a7dec579cb8d87d4","repo":"calesthio/OpenMontage","slug":"error-npm-is-required-but-was-not-found-on-path","errorCode":null,"errorMessage":"Error: npm is required but was not found on PATH.","messagePattern":"Error: npm is required but was not found on PATH\\.","errorType":"console","errorClass":"SystemExit","httpStatus":null,"severity":"error","filePath":"render_demo.py","lineNumber":55,"sourceCode":"        return {}\n    return {path.stem: path for path in sorted(PROPS_DIR.glob(\"*.json\"))}\n\n\ndef find_command(*names: str) -> str | None:\n    for name in names:\n        resolved = shutil.which(name)\n        if resolved:\n            return resolved\n    return None\n\n\ndef ensure_demo_environment() -> str:\n    if not find_command(\"node\", \"node.exe\"):\n        raise SystemExit(\"Error: Node.js is required. Install it from https://nodejs.org/\")\n\n    npm_cmd = find_command(\"npm.cmd\", \"npm\", \"npm.exe\")\n    if not npm_cmd:\n        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.\")","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/render_demo.py#L37-L73","documentation":"Raised by render_demo.py's ensure_demo_environment() as SystemExit when none of 'npm.cmd', 'npm', 'npm.exe' resolves on PATH. npm normally ships inside the Node.js distribution, so this usually means Node is installed in a nonstandard way (node binary copied without its npm sibling), PATH points at a partial Node install, or on Windows npm exists only as npm.cmd in a directory not on PATH.","triggerScenarios":"Running render_demo.py when node resolves but the npm launcher script doesn't — e.g. a manually extracted node binary, a stripped-down container image, or Windows where the npm.cmd directory (nodejs install dir) isn't on PATH.","commonSituations":"Docker images that copy only the node binary; Windows PATH edited to include a different directory than the one holding npm.cmd; broken half-updated Node installation.","solutions":["Reinstall Node.js from the official installer/package manager so node and npm land in the same directory on PATH.","On Windows, verify the Node install dir (e.g. C:\\Program Files\\nodejs) containing npm.cmd is on PATH.","In stripped containers, switch to a full node image (e.g. node:<version>-slim) instead of a hand-copied binary."],"exampleFix":"# Dockerfile — before\nCOPY node /usr/local/bin/node  # npm missing\n\n# Dockerfile — after\nFROM node:22-slim\nRUN apt-get update && apt-get install -y python3","handlingStrategy":"validation","validationCode":"import shutil\n\nif not any(shutil.which(n) for n in (\"npm.cmd\", \"npm\", \"npm.exe\")):\n    raise SystemExit(\"npm not found — reinstall Node.js so node and npm share a directory on PATH.\")","typeGuard":"import shutil\n\ndef npm_available() -> bool:\n    return any(shutil.which(n) for n in (\"npm.cmd\", \"npm\", \"npm.exe\"))","tryCatchPattern":"try:\n    npx = ensure_demo_environment()\nexcept SystemExit as e:\n    print(f\"Environment not ready: {e}\")\n    return 1","preventionTips":["Install Node from official packages so node/npm/npx ship together.","On Windows, keep the nodejs install directory on PATH.","In containers, use official node images instead of copied binaries."],"tags":["environment","npm","prerequisites","rendering"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}