google/zx · critical · Fail
No quote function is defined: ${Fail.DOCS_URL}/quotes
Error message
No quote function is defined: ${Fail.DOCS_URL}/quotes What it means
Thrown by ProcessPromise.build() when $.quote is undefined. zx needs a shell-specific quoting function to safely interpolate arguments; quote is normally assigned by useBash()/usePwsh()/usePowerShell(). At module load zx calls useBash(); if bash is not found, which.sync throws and the assignment is skipped inside an empty try/catch, leaving $.quote undefined, so the very first `$` call hits this guard. See /quotes.
Source
Thrown at src/core.ts:296
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'
const self = thisView on GitHub (pinned to 00a2c484e2)
Solutions
- Install bash in the environment (`apk add bash`, `apt-get install -y bash`).
- Switch to a configured shell helper: `usePwsh()` or `usePowerShell()`.
- Provide both shell and quote explicitly: `$.shell = '/bin/sh'; $.quote = quote` (import the built-in `quote` for POSIX shells).
- Set `$.shell = true` and ensure bash exists so auto-detection works.
Example fix
// Dockerfile before FROM alpine RUN npm i -g zx // after: install bash so useBash() succeeds and $.quote gets set FROM alpine RUN apk add --no-cache bash && npm i -g zx
Defensive patterns
Strategy: validation
Validate before calling
import { $, quote } from 'zx'
function ensureQuoteFn(): void {
if (typeof $.quote !== 'function') {
// POSIX fallback when bash is absent
$.shell = $.shell || '/bin/sh'
$.quote = quote
}
}
ensureQuoteFn() Type guard
const hasQuoteFn = (v: unknown): v is (s: string) => string => typeof v === 'function'
Try / catch
import { Fail, quote } from 'zx'
try {
await $`echo hi`
} catch (e) {
if (e instanceof Fail && /No quote function is defined/.test(e.message)) {
$.quote = quote
await $`echo hi`
} else throw e
} Prevention
- Install bash in minimal Docker images (apk add bash / apt-get install -y bash).
- When setting a custom $.shell, always pair it with a matching $.quote (use built-in quote for POSIX shells).
- Prefer useBash()/usePwsh()/usePowerShell() helpers over manual shell assignment.
When it happens
Trigger: Running zx on a system without bash (Alpine, distroless, minimal containers) with no other shell configured; setting $.shell to a custom path without also providing $.quote; overriding Options in a way that drops the quote key.
Common situations: Docker `alpine`/scratch images without bash; CI on a minimal image; custom shells (fish, sh, busybox) set via $.shell but with no matching quote function; Node runtimes where bash is not on PATH.
Related errors
- No shell is available: ${Fail.DOCS_URL}/shell
- 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/43b8745fc747a352.
Report an issue: GitHub.