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
- Restore haCmd.Stderr to an *os.File assignment in the calling code
- Use an official limactl binary
- 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
- Keep haCmd.Stderr as *os.File in all start paths
- For log capture in patches, drain an os.Pipe in a goroutine instead of swapping the writer
- Test foreground mode on unix in CI
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
- expected haCmd.Stdout 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/e3515ee29eb4c9e3.
Report an issue: GitHub.