chenhg5/cc-connect · error

taskkill failed: %w: %s; process kill fallback failed: %w

Error message

taskkill failed: %w: %s; process kill fallback failed: %w

What it means

On Windows, forceKillCmd first tries `taskkill /F /T`; if that fails (and the failure is not 'process not found'), it falls back to cmd.Process.Kill(). If BOTH the taskkill invocation and the direct process-kill fallback fail, it wraps both errors into this combined error. It means the codex subprocess could not be terminated.

Source

Thrown at agent/codex/proc_windows.go:44

func forceKillCmd(cmd *exec.Cmd) error {
	if cmd == nil || cmd.Process == nil {
		return nil
	}
	killCmd := exec.Command("taskkill", "/T", "/F", "/PID", strconv.Itoa(cmd.Process.Pid))
	output, err := killCmd.CombinedOutput()
	if err == nil {
		return nil
	}
	if bytes.Contains(bytes.ToLower(output), []byte("there is no running instance")) {
		return nil
	}
	if bytes.Contains(bytes.ToLower(output), []byte("not found")) {
		return nil
	}
	if killErr := cmd.Process.Kill(); killErr == nil || errors.Is(killErr, os.ErrProcessDone) {
		return nil
	} else {
		return fmt.Errorf("taskkill failed: %w: %s; process kill fallback failed: %w", err, processKillOutput(output), killErr)
	}
}

func processKillOutput(output []byte) string {
	trimmed := strings.TrimSpace(string(output))
	if trimmed == "" {
		return "(empty output)"
	}
	return trimmed
}

View on GitHub (pinned to 4000b2338a)

Solutions

  1. Re-run the stop operation — if the process exited concurrently this is transient.
  2. Run cc-connect with sufficient privileges on Windows to force-kill child processes.
  3. Check the embedded taskkill output (first %w/%s) for the OS reason (e.g. Access Denied) and address it.
  4. Verify the codex process is not protected by security software or an elevated context.

Example fix

// before
err := agent.Stop() // combined taskkill+kill failure, process may linger
// after
err := agent.Stop()
if err != nil && strings.Contains(err.Error(), "taskkill failed") {
    log.Printf("codex kill failed, verifying PID alive: %v", err)
    // check process liveness before retrying or reporting
}
Defensive patterns

Strategy: retry

Validate before calling

// Windows: verify we can signal the process before stopping
if err := p.Signal(syscall.Signal(0)); err != nil {
    return nil // already gone; no kill needed
}

Try / catch

err := agent.Stop()
if err != nil && strings.Contains(err.Error(), "taskkill failed") {
    log.Warn("codex kill failed; checking liveness", "err", err)
    if alive(pid) { time.Sleep(500 * time.Millisecond); err = agent.Stop() }
}

Prevention

When it happens

Trigger: Windows builds only: taskkill returns a non-'not found' error AND cmd.Process.Kill() fails with something other than os.ErrProcessDone — e.g. insufficient privileges, process already exited in a way Kill reports, or access denied to the child tree.

Common situations: Killing a process owned by another user/elevated session; antivirus or job-object policies blocking termination; the process exiting concurrently between the two attempts; running without the privileges taskkill /F requires.

Related errors


AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06). Data as JSON: /api/errors/420288ca101f581b. Report an issue: GitHub.