google/zx · error · Fail

Too late to abort the process.

Error message

Too late to abort the process.

What it means

Thrown by ProcessPromise.abort() when the process has already settled (fulfilled or rejected). Once a process exits, there is no live child to abort, so zx refuses rather than silently no-op. The guard checks isSettled() (output already assigned).

Source

Thrown at src/core.ts:437

    if (this.isSettled()) return
    this._output = output
    ProcessPromise.bus.unpipeBack(this)
    if (output.ok || this.isNothrow()) {
      this._stage = 'fulfilled'
      this._resolve(output)
    } else {
      this._stage = 'rejected'
      if (legacy) {
        this._resolve(output) // to avoid unhandledRejection alerts
        throw output.cause || output
      }
      this._reject(output)
      if (this.sync) throw output
    }
  }

  abort(reason?: string) {
    if (this.isSettled()) throw new Fail('Too late to abort the process.')
    if (this.signal !== this.ac.signal)
      throw new Fail('The signal is controlled by another process.')
    if (!this.child)
      throw new Fail('Trying to abort a process without creating one.')

    this.ac.abort(reason)
  }

  kill(signal?: NodeJS.Signals | null): Promise<void> {
    if (this.isSettled()) throw new Fail('Too late to kill the process.')
    if (!this.child)
      throw new Fail('Trying to kill a process without creating one.')
    if (!this.pid) throw new Fail('The process pid is undefined.')

    return $.kill(this.pid, signal || this._snapshot.killSignal || $.killSignal)
  }

  // Configurators

View on GitHub (pinned to 00a2c484e2)

Solutions

  1. Guard the call: `if (!pp.isSettled()) pp.abort()`.
  2. Move abort into the running window (before the awaited expression).
  3. Use $.timeout / pp.timeout() for time-bounded kills instead of manual abort.

Example fix

// before
await pp
pp.abort()
// after
if (!pp.isSettled()) pp.abort()
Defensive patterns

Strategy: validation

Validate before calling

// pp.isSettled() is private; track settlement externally
let settled = false
pp.then(() => { settled = true }).catch(() => { settled = true })

function safeAbort(p: ProcessPromise): void {
  if (!settled) p.abort()
}

Try / catch

try {
  pp.abort()
} catch (e) {
  if (e instanceof Fail && /Too late to abort/.test(e.message)) {
    // already finished — nothing to do
  } else throw e
}

Prevention

When it happens

Trigger: Calling `pp.abort()` inside `.then()`, `.catch()`, or `.finally()`; after `await pp`; in a setTimeout/setInterval callback that fires after the process completed; abort logic racing with a fast command.

Common situations: Timeout/abort watchdogs that lose the race against quick commands; cleanup handlers running in finally blocks; abort wired to an event that fires post-completion.

Related errors


AI-assisted analysis of google/zx@00a2c484e2 (2026-08-13). Data as JSON: /api/errors/edf658dc9ce3eb62. Report an issue: GitHub.