Skip to content

[BUG] npx Fails to Execute Binaries Named After Shell Keywords #8190

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
2 tasks done
ycmjason opened this issue Mar 27, 2025 · 6 comments · May be fixed by #8221
Open
2 tasks done

[BUG] npx Fails to Execute Binaries Named After Shell Keywords #8190

ycmjason opened this issue Mar 27, 2025 · 6 comments · May be fixed by #8221
Labels
Bug thing that needs fixing Priority 2 secondary priority issue

Comments

@ycmjason
Copy link

ycmjason commented Mar 27, 2025

Is there an existing issue for this?

  • I have searched the existing issues

This issue exists in the latest npm version

  • I am using the latest npm

Current Behavior

When using npx to execute binaries whose names match shell keywords (e.g., select, if), the execution fails with syntax errors. This issue occurs even when the binary name is quoted using single or double quotes.

The reproduction repo can be found: https://github.com/ycmjason/npx-shell-keyword-issue

Description

npx fails to execute binaries named after shell keywords, producing syntax errors. For example:

$ npx @my-pkg/select
sh: -c: line 0: syntax error near unexpected token `newline'
sh: -c: line 0: `select'

$ npx "@my-pkg/if"
sh: -c: line 1: syntax error: unexpected end of file

Running the binaries directly using their full paths works without any issues:

$ node_modules/.bin/select
hello from select

Actual Behavior

npx fails to execute binaries named after shell keywords, producing syntax errors.

Use Case

I am attempting to port @inquirer/select to a binary under @inquirer-cli/select. As I was testing my binaries, I noticed @inquirer-cli/select is the only one that wouldn't run.

See https://github.com/fishballapp/inquirer-cli?tab=readme-ov-file#inquirer-cliselect

Expected Behavior

npx should execute binaries correctly, even if their names match shell keywords.

Steps To Reproduce

  1. Clone the following repository: npx-shell-keyword-issue.
  2. Without running npm install, execute the following commands:
    npx @my-pkg/f
    npx @my-pkg/select
    npx @my-pkg/if
    
  3. Try quoting the binary names:
    npx '@my-pkg/select'
    npx "@my-pkg/if"
    
  4. Alternatively, run the binaries directly:
    node_modules/.bin/f
    node_modules/.bin/select
    node_modules/.bin/if
    

Environment

  • npm: 10.9.2
  • Node.js: v23.10.0
  • OS Name: MacOS 14.4.1
  • System Model Name: Macbook Pro 2021 M1 MAX
  • npm config:
ini; "user" config from /Users/ycmjason/.npmrc

//npm.pkg.github.com/:_authToken = (protected)
//registry.npmjs.org/:_authToken = (protected)

; node bin location = /Users/ycmjason/n/bin/node
; node version = v23.10.0
; npm local prefix = /Users/ycmjason/Development/000-bug-repro/npx-shell-keyword-issue
; npm version = 10.9.2
; cwd = /Users/ycmjason/Development/000-bug-repro/npx-shell-keyword-issue
; HOME = /Users/ycmjason
; Run `npm config ls -l` to show all defaults.

@ycmjason ycmjason added Bug thing that needs fixing Needs Triage needs review for next steps labels Mar 27, 2025
@milaninfy milaninfy marked this as a duplicate of #8172 Mar 27, 2025
@ycmjason
Copy link
Author

ycmjason commented Mar 27, 2025

A workaround for this issue is to define a non-shell keyword name in "bin".

For example:

  "bin": {
    "inquirer-cli-select": "index.js"
  },

This changes the binary name to inquirer-cli-select instead of just select. This is a nice workaround for now!

See also: https://github.com/fishballapp/inquirer-cli/blob/main/packages/select/package.json#L7

@pandasoli
Copy link

pandasoli commented Mar 28, 2025

A better way would be fixing npm to only look for binaries/packages inside of where it installs global/local modules.

@ycmjason
Copy link
Author

@pandasoli

100%!

I wanted to help other developers facing this issue by offering a temporary workaround.

Implementing a proper fix will probably take some time. Even after the fix is shipped, libraries would probably still want to keep the workaround for a while until the majority of users have upgraded beyond the patched release.

@milaninfy milaninfy added Priority 2 secondary priority issue and removed Needs Triage needs review for next steps labels Apr 2, 2025
@pandasoli
Copy link

@ycmjason I made this wrapper for bun:

#!/usr/bin/sh -e

# Usage: remove list item
remove() {
  first=1
  item=$2
  IFS=':' set -- $1
  for dir in $@; do
    if [ "$dir" != "$item" ]; then
      if [ $first -eq 1 ]; then
        printf "$dir"
        first=0
      else
        printf ":$dir"
      fi
    fi
  done
}

PATH=$(remove "$PATH" "/bin")
PATH=$(remove "$PATH" "/usr/bin")
PATH=$(remove "$PATH" "/usr/local/bin")
PATH=$(remove "$PATH" "/sbin")
PATH=$(remove "$PATH" "/usr/sbin")
PATH=$(remove "$PATH" "/usr/local/sbin")

bun $*

It could be smaller but this way is more extendable. It doesn't work for npx unfortunately, as it requires /usr/bin/node, but this can be a place to start from.

@pandasoli
Copy link

pandasoli commented Apr 4, 2025

Btw, this is where the commands are being executed: https://github.com/npm/cli/blob/latest/lib/cli/entry.js#L58 it runs commands with exec giving as params whatever npx receives (e.g. sv create my-app - which is my problem).

It seems also to run inside another shell which makes a wrapper useless.

How I discovered it:

I took the code above and replace bun $* by /usr/bin/npx $*, added PATH=$PATH:. and created a file called "node" with this inside:

#!/usr/bin/sh -e
node $*

and running ./npx sv create my-app fails with the error that it cannot find sh. Then I linked /usr/bin/sh to the current directory (ln -s /usr/bin/sh sh) and ran ./npx sv create my-app again and it works but ofc still with the same issue.

And running just npx gives me another shell environment that I can quit with exit.

@pandasoli
Copy link

The previous pull request doesn't fix my issue. I found a way tho: removing this line https://github.com/npm/cli/blob/latest/lib/commands/exec.js#L90 solves the issue of executing programs instead of node modules.

Tho it fixes my problem this seems to be a "feature" of npm. So I'll not be able to make a pull request unless npm maintainers give up on this feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug thing that needs fixing Priority 2 secondary priority issue
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants