fix(cli): upgrade aborts with uncaught ENOEXEC on macOS when a package manager on PATH has no shebang
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 2/5
- 見積もり時間
- 1〜3時間
- 初心者へのやさしさ
- 72/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- bun, typescript
- 領域
- cli
調査の方向性
まず packages/cli/src/services/updater.ts の233行目付近にあるパッケージマネージャーのプローブから始めてください。次に、packages/util/src/cross-spawn-spawner.ts の377行目付近にある launch(...) と、packages/cli/test/updater-install.test.ts の298行目付近にある既存のパッケージマネージャーが利用できない場合のテストを読んでください。同期的な ENOEXEC エラーを再現し、プローブのエラーがどのように処理されるかを確認してください。利用できないマネージャーでも upgrade と uninstall が続行され、動作するマネージャーは引き続き検出されれば完了です。
索引モデルが issue の本文から書いたものです。
説明
Description
On macOS, opencode upgrade and opencode uninstall crash with a stack trace when a package manager on PATH is an executable script without a shebang, even one the install does not use.
OpenCode version
@opencode/cli 2.2.6 (latest on npm) in an npm global prefix. 2.2.5 behaves the same when run here. The first report, supplied rather than rerun, came from 2.2.0 with /opt/homebrew/bin/pnpm.
Plugins
None
Operating System
macOS 27.2 arm64, with npm 12.2.1, Node 26.12.1, Bun 1.4.4 and pnpm 12.16.1. Linux and Windows are not tested, so reach beyond macOS is unknown. pnpm's launcher comment says glibc's execvp retries this file under a shell, "Apple's libc does not, so on macOS a program that spawns this path itself gets ENOEXEC", and Windows cannot reach it at all.
Terminal
CLI runs used a non-interactive shell with TERM=dumb. The TUI run used a pty with TERM=xterm-256color.
Summary
Install-method detection probes npm, pnpm, bun, yarn and vp, so an npm install of OpenCode fails on a pnpm it does not use. One way to get this state is a plain npm install -g pnpm on npm 12, which blocks pnpm's install scripts and leaves its shebang-less launcher in place. That launcher still works from a shell.
Steps to reproduce
The exports keep this in throwaway directories. Executed as written on macOS:
export HOME=$(mktemp -d) NPM_CONFIG_PREFIX=$(mktemp -d)
export PATH="$NPM_CONFIG_PREFIX/bin:$PATH"
npm install -g @opencode/[email protected] --allow-scripts=@opencode/cli
npm install -g [email protected] # npm 12 blocks pnpm's install scripts
pnpm --version # prints 12.16.1 from a shell
opencode upgrade
A smaller trigger gives the same error: an executable file named pnpm or yarn containing only echo 12.16.1, first on PATH.
Expected behavior
Detection treats a package manager it cannot run as "not this one" and moves on. method() recovers probe failures with Effect.orElseSucceed, the test "method detection tolerates unavailable package managers" states that intent, and a missing executable already behaves this way. For this npm install, the upgrade should print Using method: npm and continue.
Actual behavior
Exit status 1, version unchanged. Stack frames trimmed:
┌ Upgrade
Error: ENOEXEC: unknown error, posix_spawn '<prefix>/bin/pnpm'
at spawn (node:child_process:727:35)
at AppProcess.run (/$bunfs/root/chunk-cd0exa2g.js:7:1712)
at cli.upgrade (/$bunfs/root/chunk-cd0exa2g.js:7:21641)
Other results on the latest release:
| Condition | Result |
|---|---|
No shebang-less manager on PATH, opencode upgrade |
Using method: npm, exit 0 |
Shebang-less pnpm, opencode upgrade 2.2.5 --method npm |
Installs 2.2.5, exit 0 |
Shebang-less file named yarn, opencode upgrade |
Same ENOEXEC for yarn |
Shebang-less pnpm, opencode uninstall, with or without --dry-run |
Same ENOEXEC |
pnpm reinstalled with --allow-scripts=pnpm (the file becomes Mach-O), opencode upgrade and opencode uninstall --dry-run |
Both report npm, exit 0 |
With both Node and Bun, child_process.spawn throws ENOEXEC synchronously on this file, while a missing file emits an asynchronous error event. launchProcess handles only the event, so the throw becomes an Effect defect, which orElseSucceed does not recover. Running AppProcess.run(...).pipe(Effect.orElseSucceed(...)) with the real spawner from dev showed the split: the missing file recovered and the shebang-less file escaped as Error: ENOEXEC.
pnpm treats this launcher as a degraded state and tells users to reinstall, so that install is worth repairing. An unusable pnpm should still not block upgrading an npm install, and the stack trace names no next step.
Evidence
- Expected source: the probe recovery at
updater.ts#L233and the test atupdater-install.test.ts#L298, both ondev. - Failure source: the output above from the steps above, and the
launch(...)call atcross-spawn-spawner.ts#L377.updater.ts,cross-spawn-spawner.ts,process.tsandupgrade.tsare identical between the latest release tag and thatdevcommit. - Evidence provenance: observed
- Local verification: reproduced
- Reproduction completeness: complete
Restoration check
On the same setup with a build containing the fix, opencode upgrade prints Using method: npm and continues with no ENOEXEC, and opencode uninstall --dry-run reaches Dry run - no changes made. As a control, a working pnpm or yarn that owns the install must still be detected as that method.
References
- #58685 and open PR #58722 concern the same synchronous spawn throw in a different failure:
EPERMfromgiton Windows failing a session step throughSnapshot.capture. That PR also wraps thislaunch(...)call. I applied the same try/catch locally ondevand the probe above then recovered for the shebang-less file. I did not build a CLI with it, soopencode upgradeitself is untested with that change. - #57579 is a different symptom on Windows: detection finishes and reports that it could not detect the method.
Triage assessment
- Impact level: P2
- Assessment status: supported
- Impact basis: On macOS,
opencode upgradeandopencode uninstallfail on every run for a machine in this state, with no next step. Only machines with such a package manager onPATHare affected, the installed OpenCode keeps working, and the TUI started normally in the one 25-second run tried, though its update check's outcome is not established. - Workaround status: available
- Workaround basis:
opencode upgrade <version> --method npmskips detection and installed the requested version with the shebang-lesspnpmonPATH; on 2.2.5 it leaves the package's postinstall stub, which #51554 fixed for the latest release.npm install -g [email protected] --allow-scripts=pnpmremoves the trigger, and bothopencode upgradeandopencode uninstall --dry-runthen pass.opencode uninstallhas no--methodflag.
- 主要言語
- TypeScript
- スター
- 224k
- フォーク
- 30k
- 平均マージ
- 4時間 44分
- マージ済み PR(30日)
- 513
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
anomalyco/opencode のほかの issue
-
pending close triaging
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
anomalyco/opencode#62582 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
pending close triaging
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
anomalyco/opencode#62403 · コメント 3 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
anomalyco/opencode#62374 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
anomalyco/opencode#62362 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
reproduced
難易度 2/5 1〜3時間 初心者へのやさしさ 63/100
anomalyco/opencode#62343 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
anomalyco/opencode の issue をすべて見る
似ている issue
-
bug
難易度 2/5 1〜3時間 初心者へのやさしさ 88/100
メンテナーはふだん 1 日以内に返信
-
feature request
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
callstack/react-native-paper#5189 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
live-codes/livecodes#1079 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
Add: ESP 2 ROオープンapproved check:passed streams:add
難易度 2/5 1〜3時間 初心者へのやさしさ 66/100
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
メンテナーはふだん 1 日以内に返信