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
forceKillCmd (agent/claudecode/proc_windows.go:69) hard-kills the whole descendant tree with 'taskkill /T /F'. If taskkill fails (and it isn't the benign not-running case), it falls back to cmd.Process.Kill(); if that also fails, it reports 'taskkill failed: %w: %s; process kill fallback failed: %w' containing both the taskkill error/output and the Kill error. This means the Claude Code process tree could not be force-terminated and may still be running.
Source
Thrown at agent/claudecode/proc_windows.go:69
}
// forceKillCmd taskkill /T /F's the entire descendant tree rooted at cmd.
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 isTaskkillNotRunning(output) {
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 isTaskkillNotRunning(output []byte) bool {
lower := bytes.ToLower(output)
return bytes.Contains(lower, []byte("there is no running instance")) ||
bytes.Contains(lower, []byte("not found"))
}
func processKillOutput(output []byte) string {
trimmed := strings.TrimSpace(string(output))
if trimmed == "" {
return "(empty output)"
}
return trimmed
}
View on GitHub (pinned to 4000b2338a)
Solutions
- Check both embedded errors: if the process actually exited (ErrProcessDone), treat the stop as successful.
- Ensure cc-connect runs as the same user (or an administrator) that spawned the Claude Code process.
- Manually verify with 'tasklist | findstr claude' whether the process is still alive; kill by PID if needed.
- If EDR/AV blocks taskkill, add an exclusion or fall back to terminating the process group via Windows job objects.
Example fix
// before
if err := session.Stop(ctx); err != nil {
panic(err)
}
// after
if err := session.Stop(ctx); err != nil {
if errors.Is(err, os.ErrProcessDone) {
return nil // already dead
}
log.Warn("force kill failed; process may still be running", "err", err)
// optionally: exec taskkill /F /PID <pid> manually and re-check
} Defensive patterns
Strategy: fallback
Try / catch
if err := session.Stop(ctx); err != nil {
if errors.Is(err, os.ErrProcessDone) {
return nil
}
// last-resort: kill by PID recorded at spawn time
if pid := session.PID(); pid > 0 {
exec.Command("taskkill", "/F", "/PID", strconv.Itoa(pid)).Run()
}
} Prevention
- Record the child PID at spawn so an out-of-band taskkill /F /PID fallback exists.
- Run cc-connect as the same user (or admin) that owns the Claude Code process.
- Check EDR/AV policies that may block taskkill on production hosts.
- Confirm with tasklist whether the process actually survived before alerting.
When it happens
Trigger: Calling Stop (force kill path) on Windows where both taskkill /T /F fails with non-not-running output and cmd.Process.Kill() returns an error other than os.ErrProcessDone.
Common situations: Killing a process started by a different user (access denied for both taskkill and Kill); process protected by AV/EDR tooling; already-exited process whose handle state confuses Kill; restricted service accounts (e.g. SYSTEM vs user session) in daemon deployments.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- taskkill failed: %w: %s
- systemd user session not available in WSL2. Add the follow
- sudo is not supported on Windows
- run_as_user is not supported on Windows
- process tree (pid %d) still alive 10s after SIGKILL reported
AI-assisted analysis of chenhg5/cc-connect@4000b2338a (2026-09-06).
Data as JSON: /api/errors/7010bab25840343f.
Report an issue: GitHub.