{"record":{"id":"78a84a044ccb4295","repo":"headroomlabs-ai/headroom","slug":"error-opencode-not-found-in-path","errorCode":null,"errorMessage":"Error: 'opencode' not found in PATH.","messagePattern":"Error: 'opencode' not found in PATH\\.","errorType":"console","errorClass":"SystemExit","httpStatus":null,"severity":"error","filePath":"headroom/cli/wrap.py","lineNumber":7284,"sourceCode":"            raise click.ClickException(\n                \"--copilot-subscription cannot be combined with --prepare-only because \"\n                \"it requires a running private seeded proxy.\"\n            )\n        subscription_resolution = _require_copilot_subscription_resolution()\n\n    # Verify the opencode binary exists BEFORE mutating any config. Otherwise a\n    # missing binary leaves headroom MCP/Serena/memory entries in the user's\n    # opencode config and an injected AGENTS.md, then errors with no cleanup --\n    # the config-before-verify anti-pattern (#1614). Siblings (claude, codex,\n    # goose, omp) already check first. `--prepare-only` intentionally writes\n    # config without launching, so it is exempt.\n    opencode_bin: str | None = None\n    if not prepare_only:\n        opencode_bin = shutil.which(\"opencode\")\n        if not opencode_bin:\n            click.echo(\"Error: 'opencode' not found in PATH.\")\n            click.echo(\"Install OpenCode: https://opencode.ai\")\n            raise SystemExit(1)\n\n    # Snapshot OpenCode config.json BEFORE any wrap-time mutation so\n    # `headroom unwrap opencode` can restore the user's pre-wrap state.\n    _opencode_config_file, _opencode_backup_file = opencode_config_paths()\n    snapshot_opencode_config_if_unwrapped(_opencode_config_file, _opencode_backup_file)\n\n    # Register headroom MCP server in OpenCode config so OpenCode can\n    # call headroom_retrieve on compression markers from the proxy.\n    if not no_mcp:\n        from headroom.mcp_registry import OpencodeRegistrar\n\n        _setup_headroom_mcp(OpencodeRegistrar(), port, verbose=verbose, force=True)\n    elif verbose:\n        click.echo(\"  Skipping MCP retrieve tool (--no-mcp)\")\n\n    if not no_serena:\n        from headroom.mcp_registry import OpencodeRegistrar\n","sourceCodeStart":7266,"sourceCodeEnd":7302,"githubUrl":"https://github.com/headroomlabs-ai/headroom/blob/322425c43bffde1ed0b64fecf3cf5951565dd82b/headroom/cli/wrap.py#L7266-L7302","documentation":"Thrown by `headroom wrap opencode` when the `opencode` binary cannot be found via shutil.which. Per the code comment, the check deliberately runs BEFORE any config mutation (MCP registration, Serena/memory entries, AGENTS.md injection) so a missing binary never leaves stale headroom entries in the user's opencode config — the fix for issue #1614. `--prepare-only` is exempt because it intentionally writes config without launching.","triggerScenarios":"Running `headroom wrap opencode` without `--prepare-only` when `opencode` is not on PATH. The check fires before snapshot_opencode_config_if_unwrapped and before _setup_headroom_mcp, so no config is touched when it raises.","commonSituations":"OpenCode installed via a version manager (npm global prefix, bun, cargo) whose bin dir is not on PATH; running in CI where OpenCode was never installed; stale shell after a fresh install; SSH session with a minimal PATH.","solutions":["Install OpenCode (https://opencode.ai), typically `npm install -g opencode-ai`, in the same environment headroom runs from","Add the install prefix's bin directory to PATH (check `npm config get prefix`) and re-run","Confirm with `which opencode` before retrying `headroom wrap opencode`","If you only need the wrap-time config prepared (MCP entries, snapshot), pass `--prepare-only` — it writes config without requiring the binary"],"exampleFix":"# before\nheadroom wrap opencode\n# Error: 'opencode' not found in PATH.\n\n# after\nnpm install -g opencode-ai\nhash -r  # refresh shell command cache\nheadroom wrap opencode","handlingStrategy":"validation","validationCode":"import shutil\n\nif shutil.which(\"opencode\") is None:\n    raise SystemExit(\"opencode missing on PATH — run `npm install -g opencode-ai` first\")","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Keep the npm global bin dir on PATH across nvm/node version switches","Script the wrap step only after a `which opencode` probe succeeds","Rely on headroom's verify-before-mutate behavior: a failed launch leaves config untouched, so retrying after install is safe"],"tags":["cli","path","dependency","opencode","wrap","config-safety"],"backgroundTag":null,"analyzedSha":"322425c43bffde1ed0b64fecf3cf5951565dd82b","analyzedAt":"2026-08-15T01:03:05.481Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}