lima-vm/lima · error

failed to unmount %#q: %w (output=%#q)

Error message

failed to unmount %#q: %w (output=%#q)

What it means

Umount() on macOS runs the external `umount <mnt>` command and, on non-zero exit, returns this error wrapping the exit error plus the command's combined output. It signals that the kernel/refused unmount of the given path.

Source

Thrown at pkg/osutil/mount_darwin.go:35

func Mount(ctx context.Context, fs, dev, mnt string, options []string) error {
	args := []string{"-t", fs}
	if len(options) > 0 {
		args = append(args, "-o", strings.Join(options, ","))
	}
	args = append(args, dev, mnt)
	cmd := exec.CommandContext(ctx, "mount", args...)
	logrus.Debugf("Executing command: %v", cmd.Args)
	if output, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("failed to mount %#q on %#q: %w (output=%#q)", dev, mnt, err, output)
	}
	return nil
}

func Umount(ctx context.Context, mnt string) error {
	cmd := exec.CommandContext(ctx, "umount", mnt)
	logrus.Debugf("Executing command: %v", cmd.Args)
	if output, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("failed to unmount %#q: %w (output=%#q)", mnt, err, output)
	}
	return nil
}

View on GitHub (pinned to dd909d0973)

Solutions

  1. Read the `output=` field — umount reports 'busy' vs 'not currently mounted' distinctly.
  2. For busy mounts, find and stop processes using it (lsof +f -- <mnt> or diskutil unmount force).
  3. Ignore 'not mounted' errors as idempotent cleanup if appropriate.
  4. Retry after the consumer (VM) has fully exited.

Example fix

// before: umount while guestagent still running -> busy
// after: stop VM first, then umount with retry
if err := osutil.Umount(ctx, mnt); err != nil && !strings.Contains(err.Error(), "not currently mounted") { return err }
Defensive patterns

Strategy: retry

Validate before calling

// only attempt umount if it is actually a mount point
out, _ := exec.Command("mount").Output()
if !bytes.Contains(out, []byte(mnt)) {
    return nil // already unmounted; skip
}

Try / catch

err := osutil.Umount(ctx, mnt)
if err != nil && strings.Contains(err.Error(), "busy") {
    time.Sleep(500 * time.Millisecond)
    err = osutil.Umount(ctx, mnt) // retry after consumers exit
}

Prevention

When it happens

Trigger: Umount is called on a path that is still busy (open files, running processes), not a mount point, or requires privileges and lacks them; the umount subprocess exits non-zero.

Common situations: Tearing down a Lima instance while a VM process still holds the mount; unmounting an already-unmounted path; resource busy during shutdown sequencing.

Related errors


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