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` to terminate the copilot process tree, then falls back to Go's cmd.Process.Kill(). Only if BOTH mechanisms fail does it return "taskkill failed: %w: %s; process kill fallback failed: %w", wrapping the taskkill error, its captured output, and the Process.Kill error.

Source

Thrown at agent/copilot/proc_windows.go:51

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. Check the embedded taskkill output string (via %s) for the root cause — access denied is the most common
  2. Run cc-connect with sufficient privileges, or verify the process belongs to the same user
  3. Treat the session as already dead if the process had exited — restart the session rather than retrying the kill
  4. On non-Windows CI ensure this code path (proc_windows.go) is not being executed unintentionally

Example fix

// before: blindly retrying the same kill
return forceKillCmd(cmd)
// after: accept ErrProcessDone / already-exited as success, else restart session
if errors.Is(killErr, os.ErrProcessDone) { return nil }
slog.Warn("copilot: force kill failed", "err", err); return startNewSession(ctx)
Defensive patterns

Strategy: fallback

Validate before calling

// pre-check on Windows before relying on taskkill
if _, err := exec.LookPath("taskkill"); err != nil {
    slog.Warn("taskkill unavailable, will rely on Process.Kill fallback")
}

Try / catch

err := forceKillCmd(cmd)
if err != nil {
    slog.Warn("copilot: force kill failed", "err", err)
    // treat the session as dead and rebuild it
    return startNewSession(ctx)
}

Prevention

When it happens

Trigger: Calling forceKillCmd on a Windows system where taskkill returns a non-"not found" error (bad flags, access denied, process already re-parented) and the subsequent Process.Kill also fails (process already exited, ErrPermission, handle invalid).

Common situations: Insufficient privileges to force-kill a process owned by another user; antivirus blocking taskkill; the process exited between detection and kill so the PID is stale; taskkill.exe missing from PATH while the direct kill also fails.

Related errors


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