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
- Set a valid shell: `$.shell = '/bin/bash'` or `$.shell = true` (let zx auto-detect bash).
- Remove an empty `--shell=` flag from the invocation.
- Call a shell helper: `useBash()`, `usePwsh()`, or `usePowerShell()`.
- 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
- Never set $.shell to '' / false / null intending to 'disable' the shell — it only breaks build().
- Centralize shell configuration in one bootstrap module so it is never accidentally cleared.
- In custom Options objects, always include a valid shell key before spreading onto $.
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
- No quote function is defined: ${Fail.DOCS_URL}/quotes
- Malformed command at ${$.from}
- sync mode does not allow async command resolution
- Blob is not supported in this environment. Provide a polyfil
AI-assisted analysis of google/zx@00a2c484e2 (2026-08-13).
Data as JSON: /api/errors/9c282fe6a7fdec18.
Report an issue: GitHub.