Skip to content

Codex plugin commands fail with command not found: node on Mac App #105

Open

Description

@TobiReventic

When using the Codex plugin in Claude Code on macOS, all !-pattern commands (/codex:status, /codex:result, /codex:cancel) and lifecycle hooks fail with:

(eval):1: command not found: node

Root cause: The plugin's !-pattern commands and hooks invoke node without an absolute path. The shell environment used for !-commands and hooks does not load shell init files (.zshenv, .zshrc), so only the minimal system PATH (/usr/bin:/bin:/usr/sbin:/sbin) is available. On macOS, Node.js is typically installed in /usr/local/bin or /opt/homebrew/bin, neither of which is in that minimal PATH.

Affected files:

commands/status.md, commands/result.md, commands/cancel.md — !-commands use bare node
hooks/hooks.json — all three hooks (SessionStart, SessionEnd, Stop) use bare node
Workaround: Replace node with /usr/local/bin/node in all affected files and update allowed-tools: Bash(node:) to Bash(/usr/local/bin/node:). This fix is lost on plugin updates since the files live in the plugin cache.

Suggested fix: Use an absolute path, #!/usr/bin/env node, or resolve the node binary path at plugin install time. Alternatively, ensure the !-command shell inherits a reasonable PATH (e.g. by sourcing ~/.zshenv).

Activity

  1. 7vf7gcpwsy-create commented on Apr 11, 2026

    @7vf7gcpwsy-create

    Hit this too — confirming on Apple Silicon + Claude.app desktop (launchd-spawned, so bash -c inherits only /usr/bin:/bin:/usr/sbin:/sbin, and .zshenv doesn't help because the Bash tool isn't zsh).

    Additional affected files not listed in the original report:

    • agents/codex-rescue.md — the subagent definition invokes bare node
    • commands/rescue.md — same, plus allowed-tools: Bash(node:*) needs updating to match
    • Both of the above also exist under plugins/marketplaces/openai-codex/plugins/codex/ and need the same fix

    The rescue path has a worse failure mode than the other commands. When /codex:rescue or the codex-rescue subagent fails to spawn because node isn't found, Claude Code doesn't surface the error — instead it violates the subagent spec and hallucinates a response as if it had actually consulted Codex. The user sees a plausible-looking "Codex says..." reply that was entirely fabricated. This is significantly more dangerous than the visible command not found from /codex:status etc., because there's no signal that anything went wrong.

    Local workaround I've been running since 2026-04-07: replace bare node with /opt/homebrew/bin/node (or /usr/local/bin/node on Intel) in all 4 rescue files, and update allowed-tools in commands/rescue.md to include Bash(/opt/homebrew/bin/node:*). Has to be re-applied after every /plugin update.

    Preferred upstream fix (in priority order):

    1. Resolve the node path at plugin install time and write it into the command files
    2. Use process.execPath from within any already-running Node context and pass it down
    3. Shell out to /usr/bin/env node in the !-pattern commands (less robust — /usr/bin/env will still fail to find node if PATH is minimal)

    Option 1 is the cleanest since it handles Intel Mac, Apple Silicon, nvm/mise/volta, and Linux uniformly.

  2. astradevkin commented on Aug 19, 2026

    @astradevkin

    Still reproducible on plugin v1.0.6 (Claude Code, macOS).

    Trigger: the failure only appears in launch contexts whose inherited PATH lacks the Homebrew prefix — notably when Claude Code is started by macOS itself (Desktop app / launchd, whose default PATH is /usr/bin:/bin:/usr/sbin:/sbin) and over non-interactive SSH. Terminal-launched sessions inherit a full PATH and never see it, which is why this reads as intermittent.

    Mechanism: hooks are executed via sh -c and inherit the parent environment verbatim — the docs state this — so a bare node in hooks/hooks.json resolves only if the launching process already had Homebrew on PATH. Both session-lifecycle-hook.mjs (SessionStart/SessionEnd) and stop-review-gate-hook.mjs are affected, and per this thread the !-pattern commands are too.

    Workaround that does not involve editing the plugin cache (the cache edit works but is silently discarded when a new version directory is installed and installPath repoints): set a complete PATH in the env map of user settings.json. Verified: hook processes, MCP server processes, and the Bash tool all then receive that value. Two caveats worth knowing — it replaces PATH rather than prepending, so the value must be complete; and env's scope is not currently documented as covering hooks, so this is empirical rather than guaranteed.

    A fix at the plugin's end — resolving an absolute interpreter path at install time, or documenting the PATH requirement — would remove the need for either workaround.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions