lima-vm/lima · error
failed to kill process with pid %d: %w
Error message
failed to kill process with pid %d: %w
What it means
Lima's usernet network Stop() reads the daemon PID from the pidfile and sends SIGINT via osutil.SysKill. When the kill syscall fails (process no longer exists, permission denied, etc.), the underlying OS error is wrapped with the PID and returned, stopping network shutdown.
Source
Thrown at pkg/networks/usernet/recoincile.go:148
func Stop(ctx context.Context, name string) error {
logrus.Debugf("Make sure usernet network is stopped")
pidFile, err := PIDFile(name)
if err != nil {
return err
}
pid, _ := store.ReadPIDFile(pidFile)
if pid != 0 {
logrus.Debugf("Stopping usernet daemon")
err = writeLeases(ctx, name)
if err != nil {
return err
}
if err := osutil.SysKill(pid, osutil.SigInt); err != nil {
logrus.Error(err)
return fmt.Errorf("failed to kill process with pid %d: %w", pid, err)
}
}
// wait for daemons to terminate (up to 5s) before stopping, otherwise the sockets may not get deleted which
// will cause subsequent start commands to fail.
startWaiting := time.Now()
for {
if pid, _ := store.ReadPIDFile(pidFile); pid == 0 {
break
}
if time.Since(startWaiting) > 5*time.Second {
logrus.Infof("usernet network still running after 5 seconds. Attempting to forcibly kill")
if err := osutil.SysKill(pid, osutil.SigKill); err != nil {
logrus.Error(err)
}
break
}
time.Sleep(500 * time.Millisecond)View on GitHub (pinned to dd909d0973)
Solutions
- Verify the daemon is actually running: ps -p <pid>; if it is gone, the error is harmless — remove the stale pidfile under <LIMA_HOME>/networks/user-v2 and retry.
- Check process ownership/permissions; run limactl as the same user that started the network, or fix permission to signal the PID.
- Delete the stale pidfile (<LIMA_HOME>/_config pidfile path for the network) and re-run limactl start to restart the usernet daemon cleanly.
- If SIGINT keeps failing, kill -9 the leftover process manually and clean up sockets in the usernet dir.
Example fix
// before
if err := osutil.SysKill(pid, osutil.SigInt); err != nil {
return fmt.Errorf("failed to kill process with pid %d: %w", pid, err)
}
// after
if err := osutil.SysKill(pid, osutil.SigInt); err != nil {
if errors.Is(err, os.ErrProcessDone) {
return nil // process already exited; stale pidfile
}
return fmt.Errorf("failed to kill process with pid %d: %w", pid, err)
} Defensive patterns
Strategy: try-catch
Validate before calling
const pid = fs.readFileSync(path.join(limaHome,'networks/user-v2/<name>/pid'),'utf8').trim();
if (pid) {
try { process.kill(Number(pid), 0); } catch (e) {
// stale pidfile: daemon already dead; safe to clean up pidfile and sockets
}
} Type guard
function isKillFailure(err) {
return err != null && /failed to kill process with pid \d+/.test(err.message);
} Try / catch
try {
await stopNetwork(name);
} catch (err) {
if (/failed to kill process with pid/.test(err.message)) {
// inspect ownership (ESRCH vs EPERM), remove stale pidfile, retry once
} else throw err;
} Prevention
- Always stop instances with the same user that started them.
- Periodically clean stale pidfiles under <LIMA_HOME>/networks/.
- Check `ps -p <pid>` before assuming the error is fatal.
- Keep lima upgraded; newer versions handle already-exited daemons more gracefully.
When it happens
Trigger: Calling usernet.Stop(ctx, name) (via limactl stop / stopNetwork) when the pidfile contains a PID that has already exited (ESRCH), or when the lima user lacks permission to signal the process (EPERM), or the process is a zombie/owned by another user.
Common situations: Stale PID files left after a crash of the usernet/vde daemon; running limactl as a different user than the one that started the VM; the daemon died between reading the PID file and sending the signal.
Related errors
- failed to stop usernet %#q: %w
- usernet unable to resolve IP for SSH forwarding
- UDPFileConn connection closed
- network %#q already exists
- network mode %#q does not support specifying gateway
AI-assisted analysis of lima-vm/lima@dd909d0973 (2026-09-01).
Data as JSON: /api/errors/c76824a2e8c3e03b.
Report an issue: GitHub.