lima-vm/lima · error

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

Error message

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

What it means

execHostAgentForeground requires haCmd.Stdout to be an *os.File so it can be passed through / reused for foreground execution and log writing. This is an internal invariant: StartWithPaths sets haCmd.Stdout to an *os.File before calling this; failing the assertion means internal wiring changed incorrectly.

Source

Thrown at pkg/instance/start_unix.go:23

package instance

import (
	"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

View on GitHub (pinned to dd909d0973)

Solutions

  1. Revert local modifications so StartWithPaths keeps assigning *os.File to haCmd.Stdout
  2. Use an unmodified limactl build from an official release
  3. If hacking on lima, wrap the writer with os.Pipe and pass the file end instead

Example fix

// before
haCmd.Stdout = &buf // *bytes.Buffer
// after
f, _ := os.CreateTemp("", "ha-stdout")
haCmd.Stdout = f // *os.File
Defensive patterns

Strategy: type-guard

Validate before calling

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

Type guard

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

Try / catch

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

Prevention

When it happens

Trigger: Only reachable when the internal code path changes — e.g. a fork/patch that assigns an io.Writer (bytes.Buffer, pipe) to haCmd.Stdout before calling execHostAgentForeground on a platform where foreground mode is implemented (unix).

Common situations: Custom builds or patches to lima's start path; end users should never see this unless running modified limactl.

Related errors


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