{"record":{"id":"739b82b1ae66c913","repo":"google/zx","slug":"malformed-command-at-from","errorCode":null,"errorMessage":"Malformed command at ${$.from}","messagePattern":"Malformed command at (.+?)","errorType":"exception","errorClass":"Fail","httpStatus":null,"severity":"error","filePath":"src/core.ts","lineNumber":298,"sourceCode":"      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'\n\n    const self = this\n    const $ = self._snapshot\n    const { id, cwd } = self","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/google/zx/blob/00a2c484e219c2e84bfc3a199febf7fbce2cfbf4/src/core.ts#L280-L316","documentation":"Thrown by ProcessPromise.build() when at least one chunk of the tagged-template's `pieces` (the TemplateStringsArray) is null or undefined. In normal use pieces are always strings, so this guard catches programmatic or reflective invocation of `$` with an invalid pieces array rather than a genuine template literal. The message includes $.from (caller location) to pinpoint the call site.","triggerScenarios":"Calling the `$` function reflectively with a hand-built array containing null/undefined entries; a library/wrapper that intercepts and mutates the pieces array before forwarding to `$`; an edge case from a tagged-template polyfill.","commonSituations":"Wrapping/proxying `$` for logging or translation; dynamic command builders that construct the pieces array manually; buggy middleware that injects null placeholders.","solutions":["Use the tagged template directly: `` $`echo hi` `` instead of constructing pieces yourself.","If wrapping `$`, ensure the forwarded pieces array contains only strings (filter/null-coalesce).","Inspect the {from} location in the error message to find the offending call site.","Avoid reflective instantiation; use the public `$` API."],"exampleFix":null,"handlingStrategy":"type-guard","validationCode":"function sanitizePieces(pieces: unknown[]): string[] {\n  return pieces.map((p) => (p == null ? '' : String(p)))\n}\n\n// if you must forward to $ programmatically:\nconst clean = sanitizePieces(rawPieces)","typeGuard":"const areValidPieces = (p: unknown): p is TemplateStringsArray =>\n  Array.isArray(p) && p.every((chunk) => typeof chunk === 'string')","tryCatchPattern":"import { Fail } from 'zx'\ntry {\n  await runCustomWrapper()\n} catch (e) {\n  if (e instanceof Fail && /Malformed command at/.test(e.message)) {\n    console.error('wrapper injected null/undefined into template pieces:', e.message)\n  }\n  throw e\n}","preventionTips":["Always invoke $ as a tagged template literal — never build the pieces array by hand.","If you wrap $, pass through the original TemplateStringsArray untouched.","Filter null/undefined out of any dynamically constructed pieces before forwarding."],"tags":["template-literal","api-misuse","internals","build"],"backgroundTag":null,"analyzedSha":"00a2c484e219c2e84bfc3a199febf7fbce2cfbf4","analyzedAt":"2026-08-13T02:11:06.305Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}