{"record":{"id":"1b57fbb8dc1f9746","repo":"google/zx","slug":"inappropriate-usage-apply-instead-of-direct-ins","errorCode":null,"errorMessage":"Inappropriate usage. Apply $ instead of direct instantiation.","messagePattern":"Inappropriate usage\\. Apply \\$ instead of direct instantiation\\.","errorType":"exception","errorClass":"Fail","httpStatus":null,"severity":"error","filePath":"src/core.ts","lineNumber":845,"sourceCode":"    this._stdin.write(data, encoding, cb)\n    return this\n  }\n  private end(chunk: any, cb: any) {\n    this._stdin.end(chunk, cb)\n    return this\n  }\n  private removeListener(event: string, cb: any) {\n    this._stdin.removeListener(event, cb)\n    return this\n  }\n\n  // prettier-ignore\n  private static disarm(p: ProcessPromise, toggle = true): void {\n    Object.getOwnPropertyNames(ProcessPromise.prototype).forEach(k => {\n      if (k in Promise.prototype) return\n      if (!toggle) { Reflect.deleteProperty(p, k); return }\n      Object.defineProperty(p, k, { configurable: true, get() {\n        throw new Fail('Inappropriate usage. Apply $ instead of direct instantiation.')\n      }})\n    })\n  }\n}\n\ntype ProcessDto = {\n  code: number | null\n  signal: NodeJS.Signals | null\n  duration: number\n  error: any\n  from: string\n  store: TSpawnStore\n  delimiter?: string | RegExp\n}\n\nexport class ProcessOutput extends Error {\n  private readonly _dto!: ProcessDto\n  cause!: Error | null","sourceCodeStart":827,"sourceCodeEnd":863,"githubUrl":"https://github.com/google/zx/blob/00a2c484e219c2e84bfc3a199febf7fbce2cfbf4/src/core.ts#L827-L863","documentation":"Thrown by the static disarm() trap installed on a ProcessPromise that was constructed directly via `new ProcessPromise(executor)` instead of through the `$` tagged-template factory. When the constructor receives an executor lacking the internal SHOT snapshot, it disarms every non-Promise method so any access throws, steering you toward using `$`. This prevents callers from treating ProcessPromise like a plain subclassable Promise.","triggerScenarios":"`new ProcessPromise((res) => res())`; subclassing or reflectively instantiating ProcessPromise; copy-pasting a Promise constructor pattern.","commonSituations":"Treating ProcessPromise as a normal Promise; library code that instantiates it directly; attempting to wrap or extend the class.","solutions":["Always create commands via the tagged template: `` $`echo ok` `` or `` $({opts})`cmd` ``.","If you need a resolved ProcessOutput, construct ProcessOutput directly rather than a fake ProcessPromise.","Do not subclass or reflectively instantiate ProcessPromise."],"exampleFix":"// before\nnew ProcessPromise((resolve) => resolve())\n// after\n$`echo ok`","handlingStrategy":"type-guard","validationCode":"// Reject direct construction at the type layer; always route through $.\nfunction makeCommand(tpl: TemplateStringsArray, ...args: unknown[]) {\n  return $(tpl, ...args)\n}","typeGuard":"import { ProcessPromise } from 'zx'\nconst madeByFactory = (p: ProcessPromise): boolean =>\n  typeof (p as any).stage === 'string' // disarmed instances throw on stage access","tryCatchPattern":"try {\n  // never do: new ProcessPromise(...)\n  await $`echo ok`\n} catch (e) {\n  if (e instanceof Fail && /Apply \\$ instead of direct instantiation/.test(e.message)) {\n    throw new Error('Use the $ tagged template, not new ProcessPromise()')\n  }\n  throw e\n}","preventionTips":["Never call `new ProcessPromise(...)` — always use the `$` tagged template.","Do not subclass or reflectively instantiate ProcessPromise.","For pre-resolved outputs, build ProcessOutput directly instead of faking a ProcessPromise."],"tags":["api-misuse","factory","internals","constructor"],"backgroundTag":null,"analyzedSha":"00a2c484e219c2e84bfc3a199febf7fbce2cfbf4","analyzedAt":"2026-08-13T02:11:06.305Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}