lima-vm/lima · error

expected haCmd.Stderr to be *os.File, got %T

Error message

expected haCmd.Stderr to be *os.File, got %T

What it means

Same invariant as the Stdout check but for haCmd.Stderr: foreground execution of the hostagent needs real *os.File descriptors. A non-file writer passed to haCmd.Stderr triggers this error before the hostagent is exec'd in the foreground.

Source

Thrown at pkg/instance/start_unix.go:27

	"fmt"
	"os"
	"os/exec"
	"syscall"

	"github.com/mattn/go-isatty"
	"github.com/sirupsen/logrus"

	"github.com/lima-vm/lima/v2/pkg/osutil"
)

func execHostAgentForeground(limactl string, haCmd *exec.Cmd) error {
	haStdoutW, ok := haCmd.Stdout.(*os.File)
	if !ok {
		return fmt.Errorf("expected haCmd.Stdout to be *os.File, got %T", haCmd.Stdout)
	}
	haStderrW, ok := haCmd.Stderr.(*os.File)
	if !ok {
		return fmt.Errorf("expected haCmd.Stderr to be *os.File, got %T", haCmd.Stderr)
	}
	logrus.Info("Running the host agent in the foreground")
	if isatty.IsTerminal(os.Stdin.Fd()) || isatty.IsCygwinTerminal(os.Stdin.Fd()) {
		// Write message to standard log files to avoid confusing users
		message := "This log file is not used because `limactl start` was launched in the terminal with the `--foreground` option."
		if _, err := haStdoutW.WriteString(message); err != nil {
			return err
		}
		if _, err := haStderrW.WriteString(message); err != nil {
			return err
		}
	} else {
		if err := osutil.Dup2(int(haStdoutW.Fd()), syscall.Stdout); err != nil {
			return err
		}
		if err := osutil.Dup2(int(haStderrW.Fd()), syscall.Stderr); err != nil {
			return err
		}

View on GitHub (pinned to dd909d0973)

Solutions

  1. Restore haCmd.Stderr to an *os.File assignment in the calling code
  2. Use an official limactl binary
  3. In patches, use os.Pipe and log from the read end in a goroutine

Example fix

// before
haCmd.Stderr = osutil.NewLoggerWriter(...) // not *os.File
// after
haStderr, _ := os.OpenFile(haStderrPath, os.O_CREATE|os.O_WRONLY, 0o644)
haCmd.Stderr = haStderr
Defensive patterns

Strategy: type-guard

Validate before calling

if _, ok := haCmd.Stderr.(*os.File); !ok {
    return fmt.Errorf("callers must set haCmd.Stderr to *os.File")
}

Type guard

func ensureStderrIsFile(cmd *exec.Cmd) (*os.File, bool) {
    f, ok := cmd.Stderr.(*os.File)
    return f, ok
}

Try / catch

if err := execHostAgentForeground(limactl, haCmd); err != nil {
    if strings.Contains(err.Error(), "expected haCmd.Stderr") {
        return fmt.Errorf("internal wiring bug: %w", err)
    }
    return err
}

Prevention

When it happens

Trigger: Internal code path (or patch) assigning a non-*os.File writer (pipe, buffer, multiwriter) to haCmd.Stderr before execHostAgentForeground runs.

Common situations: Modified limactl builds; not seen with official binaries.

Related errors


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