{"record":{"id":"9c282fe6a7fdec18","repo":"google/zx","slug":"no-shell-is-available-fail-docs-url-shell","errorCode":null,"errorMessage":"No shell is available: ${Fail.DOCS_URL}/shell","messagePattern":"No shell is available: (.+?)/shell","errorType":"exception","errorClass":"Fail","httpStatus":null,"severity":"critical","filePath":"src/core.ts","lineNumber":294,"sourceCode":"\n    const snapshot = executor[SHOT]\n    if (snapshot) {\n      this._snapshot = snapshot\n      this._resolve = resolve!\n      this._reject = reject!\n      if (snapshot.halt) this._stage = 'halted'\n      try {\n        this.build()\n      } catch (err) {\n        this.finalize(ProcessOutput.fromError(err as Error), true)\n      }\n    } else ProcessPromise.disarm(this)\n  }\n  // prettier-ignore\n  private build(): void {\n    const $ = this._snapshot\n    if (!$.shell)\n      throw new Fail(`No shell is available: ${Fail.DOCS_URL}/shell`)\n    if (!$.quote)\n      throw new Fail(`No quote function is defined: ${Fail.DOCS_URL}/quotes`)\n    if ($.pieces.some((p) => p == null))\n      throw new Fail(`Malformed command at ${$.from}`)\n\n    $.cmd = buildCmd(\n      $.quote!,\n      $.pieces as TemplateStringsArray,\n      $.args\n    ) as string\n\n    if ($[SYNC] && !isString($.cmd))\n      throw new Fail('sync mode does not allow async command resolution')\n  }\n  run(): this {\n    ProcessPromise.bus.runBack(this)\n    if (this.isRunning() || this.isSettled()) return this // The _run() can be called from a few places.\n    this._stage = 'running'","sourceCodeStart":276,"sourceCodeEnd":312,"githubUrl":"https://github.com/google/zx/blob/00a2c484e219c2e84bfc3a199febf7fbce2cfbf4/src/core.ts#L276-L312","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n$.shell = ''\nawait $`echo hi`\n// after\n$.shell = true   // or useBash()\nawait $`echo hi`","handlingStrategy":"validation","validationCode":"import { $ } from 'zx'\n\nfunction ensureShell(): void {\n  const shell = $.shell as unknown\n  if (!shell || shell === '') {\n    throw new Error('$.shell is falsy — set it to a path or true before running commands')\n  }\n}\n\nensureShell()","typeGuard":"import type { Options } from 'zx'\nconst isShellSet = (v: Options['shell']): boolean =>\n  typeof v === 'string' ? v.length > 0 : v === true","tryCatchPattern":"import { Fail } from 'zx'\ntry {\n  await $`echo hi`\n} catch (e) {\n  if (e instanceof Fail && /No shell is available/.test(e.message)) {\n    $.shell = true; useBash()\n  }\n  throw e\n}","preventionTips":["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 $."],"tags":["shell","config","environment","build"],"backgroundTag":null,"analyzedSha":"00a2c484e219c2e84bfc3a199febf7fbce2cfbf4","analyzedAt":"2026-08-13T02:11:06.305Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}