{"record":{"id":"b5be4476bf7007f8","repo":"google/zx","slug":"trying-to-abort-a-process-without-creating-one","errorCode":null,"errorMessage":"Trying to abort a process without creating one.","messagePattern":"Trying to abort a process without creating one\\.","errorType":"exception","errorClass":"Fail","httpStatus":null,"severity":"error","filePath":"src/core.ts","lineNumber":441,"sourceCode":"      this._stage = 'fulfilled'\n      this._resolve(output)\n    } else {\n      this._stage = 'rejected'\n      if (legacy) {\n        this._resolve(output) // to avoid unhandledRejection alerts\n        throw output.cause || output\n      }\n      this._reject(output)\n      if (this.sync) throw output\n    }\n  }\n\n  abort(reason?: string) {\n    if (this.isSettled()) throw new Fail('Too late to abort the process.')\n    if (this.signal !== this.ac.signal)\n      throw new Fail('The signal is controlled by another process.')\n    if (!this.child)\n      throw new Fail('Trying to abort a process without creating one.')\n\n    this.ac.abort(reason)\n  }\n\n  kill(signal?: NodeJS.Signals | null): Promise<void> {\n    if (this.isSettled()) throw new Fail('Too late to kill the process.')\n    if (!this.child)\n      throw new Fail('Trying to kill a process without creating one.')\n    if (!this.pid) throw new Fail('The process pid is undefined.')\n\n    return $.kill(this.pid, signal || this._snapshot.killSignal || $.killSignal)\n  }\n\n  // Configurators\n  stdio(\n    stdin: IOType | StdioOptions,\n    stdout: IOType = 'pipe',\n    stderr: IOType = 'pipe'","sourceCodeStart":423,"sourceCodeEnd":459,"githubUrl":"https://github.com/google/zx/blob/00a2c484e219c2e84bfc3a199febf7fbce2cfbf4/src/core.ts#L423-L459","documentation":"Thrown by ProcessPromise.abort() when this.child is null — i.e. the underlying child process has not been spawned yet. The AbortController has nothing to signal before the process starts running.","triggerScenarios":"Calling abort() on a halted ProcessPromise (`$({halt:true})`) before .run() is invoked; aborting synchronously in the same tick as `$` creation before the spawn microtask runs; aborting a command that was never run.","commonSituations":"Halted pipelines where run() is deferred; abort wired to synchronous setup code; deferred command graphs that abort before launch.","solutions":["Ensure the process has started: for halted promises call `pp.run()` first.","Defer the abort a tick: `setImmediate(() => pp.abort())`.","Abort from the 'start' event or use $.timeout for bounded behavior."],"exampleFix":"// before\nconst pp = $({ halt: true })`sleep 10`\npp.abort()\n// after\nconst pp = $({ halt: true })`sleep 10`\npp.run()\npp.abort()","handlingStrategy":"validation","validationCode":"// child is private; ensure the process is running before aborting\nfunction abortIfRunning(pp: ProcessPromise): void {\n  if (pp.stage === 'running') pp.abort()\n  else setImmediate(() => pp.stage === 'running' && pp.abort())\n}","typeGuard":null,"tryCatchPattern":"try {\n  pp.abort()\n} catch (e) {\n  if (e instanceof Fail && /without creating one/.test(e.message)) {\n    pp.run() // for halted promises\n    pp.abort()\n  } else throw e\n}","preventionTips":["For halted pipelines, call pp.run() before abort/kill.","Defer abort with setImmediate to let the spawn microtask complete.","Abort from the 'start' event to guarantee a child exists."],"tags":["abort","lifecycle","halted","child-process"],"backgroundTag":null,"analyzedSha":"00a2c484e219c2e84bfc3a199febf7fbce2cfbf4","analyzedAt":"2026-08-13T02:11:06.305Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}