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 errView on GitHub (pinned to dd909d0973)
Solutions
- Revert local modifications so StartWithPaths keeps assigning *os.File to haCmd.Stdout
- Use an unmodified limactl build from an official release
- 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 modifying start.go, keep assigning *os.File to haCmd.Stdout/Stderr
- Add unit tests asserting the *os.File wiring before foreground exec
- Use os.Pipe/file when capturing output in patched builds
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
- expected haCmd.Stderr to be *os.File, got %T
- failed to check autostart registration: %w
- host agent process has exited: %w
- hostagent (%#q) did not start up in %v (hint: see %#q)
- exiting, status=%+v (hint: see %#q)
AI-assisted analysis of lima-vm/lima@dd909d0973 (2026-09-01).
Data as JSON: /api/errors/d4001ede552c6c06.
Report an issue: GitHub.