lima-vm/lima · error

%s daemon for %#q network %w%s

Error message

%s daemon for %#q network %w%s

What it means

Lima fails to start the network daemon (e.g. socket_vmnet) for a named network because the daemon stayed alive past the 30s startup timeout without ever writing its PID file. This is a non-transient 'stuck daemon' condition, so startDaemonWithRetry returns immediately (no retry), appending the daemon's captured stderr or a pointer to its stderr log to help diagnosis.

Source

Thrown at pkg/networks/reconcile/reconcile.go:312

				return ctx.Err()
			case <-time.After(backoff):
			}
		}
		cmd, err := startDaemon(ctx, cfg, name, daemon)
		if err != nil {
			return err // infrastructure failure (sudo/exec) — not transient
		}
		err = waitForDaemon(ctx, cmd, pidFile, startTimeout)
		if err == nil {
			return nil
		}
		// Only an early exit (the transient XPC race) is retried; everything else
		// is surfaced immediately.
		if _, ok := errors.AsType[*daemonExitedError](err); !ok {
			// A stuck (still-running) daemon gets its stderr appended; PID-read and
			// context errors propagate as-is.
			if _, ok := errors.AsType[*daemonStuckError](err); ok {
				return fmt.Errorf("%s daemon for %#q network %w%s", daemon, name, err, stderrHint(stderrLog))
			}
			return err
		}
		lastErr = err // process exited early — retry
	}
	return fmt.Errorf("%s daemon for %#q network failed to start after %d attempts: %w%s",
		daemon, name, maxAttempts, lastErr, stderrHint(stderrLog))
}

// waitForDaemon waits until the daemon writes its PID file (success), exits without
// one (returns *daemonExitedError so the caller can retry), or stays alive past
// timeout without a PID file (returns *daemonStuckError). A stuck or cancelled
// process is killed and reaped.
func waitForDaemon(ctx context.Context, cmd *exec.Cmd, pidFile string, timeout time.Duration) error {
	waitCh := make(chan error, 1)
	go func() { waitCh <- cmd.Wait() }()

	timer := time.NewTimer(timeout)

View on GitHub (pinned to dd909d0973)

Solutions

  1. Read the daemon stderr shown in the message (or the referenced log file under ~/.lima/networks) to see where the daemon is blocked
  2. Kill any leftover daemon processes (stale socket_vmnet instances) and delete stale PID files, then retry limactl start
  3. Verify the socketVMNet binary path and network switch device in networks.yaml are correct
  4. Reinstall/upgrade socket_vmnet (e.g. brew upgrade socket_vmnet) if the binary is broken

Example fix

// before: orphaned socket_vmnet keeps running, PID file never written
$ sudo pkill -f socket_vmnet
$ rm ~/.lima/networks/lima-shared_pid
// after: retry
$ limactl start
Defensive patterns

Strategy: validation

Validate before calling

pidFile := filepath.Join(os.Getenv("HOME"), ".lima", "networks", "<name>_pid")
if data, err := os.ReadFile(pidFile); err == nil {
    var pid int
    if _, e := fmt.Sscanf(string(data), "%d", &pid); e != nil || pid <= 0 {
        os.Remove(pidFile) // stale/corrupt before starting
    }
}

Type guard

func isDaemonStuckError(err error) bool {
    var e *daemonStuckError
    return errors.As(err, &e)
}

Try / catch

if err := limactlStart(); err != nil {
    var stuck *daemonStuckError
    if errors.As(err, &stuck) {
        // kill orphaned daemon, remove PID file, retry once
    }
}

Prevention

When it happens

Trigger: Calling startNetwork/Reconcile for a sudo-managed network where the daemon process runs but never writes cfg.PIDFile(name, daemon) within 30s — e.g. socket_vmnet blocked waiting on input, a stale/hung process, or the daemon wedged before creating its PID file.

Common situations: socket_vmnet hanging after launch (wrong binary or args), a leftover orphaned daemon holding the unix socket, permission/sandbox issues making the daemon block on a resource, or a stale PID file path pointing at a directory that can't be written.

Related errors


AI-assisted analysis of lima-vm/lima@dd909d0973 (2026-09-01). Data as JSON: /api/errors/14d50d9213a51d11. Report an issue: GitHub.