google/zx · critical · Fail

No shell is available: ${Fail.DOCS_URL}/shell

Error message

No shell is available: ${Fail.DOCS_URL}/shell

What it means

Thrown by ProcessPromise.build() when the $.shell option is falsy at the moment a command is constructed. zx spawns commands through a shell, so it refuses to run if no shell is configured. The message links to the docs (/shell) for configuration guidance.

Source

Thrown at src/core.ts:294

    const snapshot = executor[SHOT]
    if (snapshot) {
      this._snapshot = snapshot
      this._resolve = resolve!
      this._reject = reject!
      if (snapshot.halt) this._stage = 'halted'
      try {
        this.build()
      } catch (err) {
        this.finalize(ProcessOutput.fromError(err as Error), true)
      }
    } else ProcessPromise.disarm(this)
  }
  // prettier-ignore
  private build(): void {
    const $ = this._snapshot
    if (!$.shell)
      throw new Fail(`No shell is available: ${Fail.DOCS_URL}/shell`)
    if (!$.quote)
      throw new Fail(`No quote function is defined: ${Fail.DOCS_URL}/quotes`)
    if ($.pieces.some((p) => p == null))
      throw new Fail(`Malformed command at ${$.from}`)

    $.cmd = buildCmd(
      $.quote!,
      $.pieces as TemplateStringsArray,
      $.args
    ) as string

    if ($[SYNC] && !isString($.cmd))
      throw new Fail('sync mode does not allow async command resolution')
  }
  run(): this {
    ProcessPromise.bus.runBack(this)
    if (this.isRunning() || this.isSettled()) return this // The _run() can be called from a few places.
    this._stage = 'running'

View on GitHub (pinned to 00a2c484e2)

Solutions

  1. Set a valid shell: `$.shell = '/bin/bash'` or `$.shell = true` (let zx auto-detect bash).
  2. Remove an empty `--shell=` flag from the invocation.
  3. Call a shell helper: `useBash()`, `usePwsh()`, or `usePowerShell()`.
  4. Ensure bash is installed so module-load auto-detection succeeds.

Example fix

// before
$.shell = ''
await $`echo hi`
// after
$.shell = true   // or useBash()
await $`echo hi`
Defensive patterns

Strategy: validation

Validate before calling

import { $ } from 'zx'

function ensureShell(): void {
  const shell = $.shell as unknown
  if (!shell || shell === '') {
    throw new Error('$.shell is falsy — set it to a path or true before running commands')
  }
}

ensureShell()

Type guard

import type { Options } from 'zx'
const isShellSet = (v: Options['shell']): boolean =>
  typeof v === 'string' ? v.length > 0 : v === true

Try / catch

import { Fail } from 'zx'
try {
  await $`echo hi`
} catch (e) {
  if (e instanceof Fail && /No shell is available/.test(e.message)) {
    $.shell = true; useBash()
  }
  throw e
}

Prevention

When it happens

Trigger: Explicitly setting `$.shell = ''`, `false`, `null`, or `0` in code; passing an empty `--shell=` CLI flag; constructing a custom Options object without a `shell` key and spreading it onto `$`; library code that conditionally resets $.shell to a falsy value.

Common situations: Disabling the shell by mistake; env/CLI providing an empty shell value; resetting $.shell in a within() scope; copy-pasted config that sets shell conditionally.

Related errors


AI-assisted analysis of google/zx@00a2c484e2 (2026-08-13). Data as JSON: /api/errors/9c282fe6a7fdec18. Report an issue: GitHub.