{"record":{"id":"a61b1295fface3e9","repo":"Graphify-Labs/graphify","slug":"claude-code-cli-not-found-on-path","errorCode":null,"errorMessage":"Claude Code CLI not found on $PATH","messagePattern":"Claude Code CLI not found on \\$PATH","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"graphify/llm.py","lineNumber":2618,"sourceCode":"            messages=[{\"role\": \"user\", \"content\": prompt}],\n        )\n        u = getattr(resp, \"usage\", None)\n        if u is not None:\n            _rec(getattr(u, \"input_tokens\", 0), getattr(u, \"output_tokens\", 0))\n        return resp.content[0].text if resp.content else \"\"\n\n    if backend == \"claude-cli\":\n        import platform, shutil, subprocess\n        # Mirror the extraction-path resolution: on Windows the npm shim is\n        # claude.cmd, which CreateProcess can't resolve from a bare \"claude\"\n        # (PATHEXT doesn't apply), so pass the resolved .cmd path explicitly.\n        claude_cmd = \"claude\"\n        if platform.system() == \"Windows\":\n            cmd_path = shutil.which(\"claude.cmd\")\n            if cmd_path:\n                claude_cmd = cmd_path\n            elif shutil.which(\"claude\") is None:\n                raise RuntimeError(\"Claude Code CLI not found on $PATH\")\n        elif shutil.which(\"claude\") is None:\n            raise RuntimeError(\"Claude Code CLI not found on $PATH\")\n        cli_args = [claude_cmd, \"-p\", \"--output-format\", \"json\", \"--no-session-persistence\"]\n        if model is not None:\n            cli_args.extend([\"--model\", mdl])\n        proc = subprocess.run(\n            cli_args,\n            input=prompt,\n            capture_output=True,\n            text=True,\n            encoding=\"utf-8\",  # Force UTF-8 — prevents UnicodeEncodeError on Windows cp1252\n            errors=\"replace\",  # Tolerate non-UTF-8 bytes (e.g. GBK/cp936 from claude.cmd on Chinese Windows)\n            timeout=_resolve_api_timeout(),\n            check=False,\n            **_no_window_kwargs(),\n        )\n        cli_error = _claude_cli_error(proc.stdout)\n        if proc.returncode != 0:","sourceCodeStart":2600,"sourceCodeEnd":2636,"githubUrl":"https://github.com/Graphify-Labs/graphify/blob/7fe58b0b0f3873be9a21c30106b8b8527c353aa6/graphify/llm.py#L2600-L2636","documentation":"RuntimeError raised by the claude-cli backend when `shutil.which(\"claude\")` finds no executable on PATH on a non-Windows system (or on Windows when neither claude.cmd nor claude resolves). graphify invokes the Claude Code CLI as a subprocess (`claude -p --output-format json`), so it hard-fails up front if the binary is missing rather than failing mid-pipeline.","triggerScenarios":"Selecting backend 'claude-cli' on Linux/macOS while `claude` is not on $PATH: graphify/llm.py:2617-2620 runs shutil.which and raises when it returns None. Happens for any LLM call (labels, dedup, extraction) once that backend is chosen.","commonSituations":"Node/npm installed the CLI under a user npm prefix (e.g. ~/.npm-global/bin) that is not on PATH in cron, CI, or a service context; nvm-managed node where the shell that installed claude differs from the one running graphify; the user installed the desktop app but never `npm install -g @anthropic-ai/claude-code`.","solutions":["Verify the CLI exists: `which claude` - if empty, install with `npm install -g @anthropic-ai/claude-code`.","If it is installed but not found, add its directory to PATH (e.g. `export PATH=\"$HOME/.npm-global/bin:$PATH\"` or the nvm bin dir) in the exact shell/service env that runs graphify.","If you cannot install the CLI, switch the backend to 'claude' (anthropic package) or another provider."],"exampleFix":"# before: backend shells out to a missing binary\n$ graphify update . --backend claude-cli\n# RuntimeError: Claude Code CLI not found on $PATH\n\n# after: install the CLI globally, then re-run\n$ npm install -g @anthropic-ai/claude-code\n$ which claude && graphify update . --backend claude-cli","handlingStrategy":"validation","validationCode":"import shutil, platform\n\ndef claude_cli_available() -> bool:\n    if platform.system() == \"Windows\":\n        return shutil.which(\"claude.cmd\") is not None or shutil.which(\"claude\") is not None\n    return shutil.which(\"claude\") is not None\n\nif not claude_cli_available():\n    raise SystemExit(\"Install Claude Code CLI: npm install -g @anthropic-ai/claude-code\")","typeGuard":null,"tryCatchPattern":"try:\n    result = call_llm(prompt, backend=\"claude-cli\")\nexcept RuntimeError as exc:\n    if \"CLI not found\" in str(exc):\n        raise SystemExit(\"claude CLI missing from PATH - install or fix PATH\") from exc\n    raise","preventionTips":["For service/cron environments, print PATH and `which claude` in a healthcheck before long jobs.","Prefer absolute paths in config if the CLI location is stable (e.g. /usr/local/bin/claude).","Remember Windows uses claude.cmd - the same check must consider PATHEXT shims."],"tags":["cli","path","environment","llm","claude"],"backgroundTag":null,"analyzedSha":"7fe58b0b0f3873be9a21c30106b8b8527c353aa6","analyzedAt":"2026-08-14T19:23:21.323Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}