Skip to content

Avoid unconditional bash execution on Windows#1417

Open
kiritocode1 wants to merge 4 commits intogoogle:mainfrom
kiritocode1:main
Open

Avoid unconditional bash execution on Windows#1417
kiritocode1 wants to merge 4 commits intogoogle:mainfrom
kiritocode1:main

Conversation

@kiritocode1
Copy link

Fixes #1331

This PR resolves a sudden crash on Windows environments when importing zx. Previously, useBash() was being called unconditionally at the module level. This checks if the platform is Windows (win32) and defaults .shell to true with the standard quote, circumventing the exception when a user on Windows doesn't easily have bash available.

Changes:

  • src/core.ts: Safely detect win32 platform before applying shell defaults.
  • test/init-win32.test.js: Added unit test to verify that loading the module on win32 correctly assigns $.shell = true.
  • .size-limit.json: Accommodated the tiny bundle size increase caused by the bugfix check.
  • build/*: Rebuilt and committed the compiled node modules.
import {$} from 'zx'

@google-cla
Copy link

google-cla bot commented Feb 23, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@kiritocode1
Copy link
Author

updated the cla lol .

@antongolub
Copy link
Collaborator

@kiritocode1,

The main question of #1331: why which.sync('bash') returns /bin/bash ref which cannot be invoked.

@kiritocode1
Copy link
Author

kiritocode1 commented Feb 23, 2026

@antongolub thank you for bringing it to my attention , I just did a workaround ,

child_process.spawn() runs in native Windows, not inside wsl. native windows has no idea what /bin/bash means it's not a valid windows filesystem path. so the spawn fails and zx crashes.

ill update the pr with the fixes .

im thinking of

a. either validate that the resolved bash is actually invocable by doing something like this :

try {
  const { shell, prefix, postfix } = $
  if (process.platform === 'win32') {
    try {
      useBash()
      // Validate that the resolved bash is actually invocable (not a broken WSL ref)
      cp.execSync(`"${$.shell}" -c "echo ok"`, {
        stdio: 'ignore',
        timeout: 5000,
      })
    } catch {
      $.shell = true
      $.prefix = ''
      $.postfix = ''
      $.quote = quote
    }
  } else {
    useBash()
  }

which adds a small latency to every import on windows while keeping the performance the same on unix and macos.

or
b. checking if the resolved path is a Unix-style path like /bin/bash
on Windows, which would indicate a non-native WSL reference (since Git Bash resolves to something like C:\Program Files\Git\bin\bash.exe) which is just static validation.

which option will work better in the long run? happy to implement either.

@antongolub
Copy link
Collaborator

The problem is broader: shell: true uses cmd.exe and requires special argument escaping logic.

@kiritocode1
Copy link
Author

The problem is broader: shell: true uses cmd.exe and requires special argument escaping logic.

I see, then what could be a better approach?

@antongolub
Copy link
Collaborator

I think we also need a comprehensive, reliable, and safe guide to installing Bash for different versions of Windows.

https://google.github.io/zx/setup#bash

@kiritocode1
Copy link
Author

I think we also need a comprehensive, reliable, and safe guide to installing Bash for different versions of Windows.

https://google.github.io/zx/setup#bash

sounds good. who do we reach out to for collaborating on this or should I take the lead?

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

zx cannot be run on Windows.

2 participants