lima-vm/lima · error

failed to create .ssh directory for user %#q: %w

Error message

failed to create .ssh directory for user %#q: %w

What it means

The agent could not create the `<homedir>/.ssh` directory (mode 0700) for the freshly created user. This directory is required to install `authorized_keys`. The error wraps the raw os.MkdirAll failure and aborts provisioning of this user.

Source

Thrown at pkg/guestagent/fakecloudinit/fakecloudinit_darwin.go:298

	if err = populateHomeDir(ctx, uid, homedir); err != nil {
		return fmt.Errorf("failed to populate home directory for user %#q: %w", u.Name, err)
	}

	cmd = exec.CommandContext(ctx, "chmod", "700", homedir)
	logrus.Infof("Executing command: %v", cmd.Args)
	if output, err := cmd.CombinedOutput(); err != nil {
		return fmt.Errorf("failed to execute command %v: %w (output=%#q)", cmd.Args, err, output)
	}

	pwPath := filepath.Join(homedir, "password")
	if err = os.WriteFile(pwPath, []byte(pw+"\n"), 0o400); err != nil {
		return fmt.Errorf("failed to write password file for user %#q: %w", u.Name, err)
	}
	logrus.Infof("Created user %#q. The password is stored in %#q", u.Name, pwPath)

	dotSSHPath := filepath.Join(homedir, ".ssh")
	if err = os.MkdirAll(dotSSHPath, 0o700); err != nil {
		return fmt.Errorf("failed to create .ssh directory for user %#q: %w", u.Name, err)
	}
	authKeysPath := filepath.Join(dotSSHPath, "authorized_keys")
	authKeysContent := strings.Join(u.SSHAuthorizedKeys, "\n")
	if err = os.WriteFile(authKeysPath, []byte(authKeysContent), 0o600); err != nil {
		return fmt.Errorf("failed to write authorized_keys file for user %#q: %w", u.Name, err)
	}
	for _, f := range []string{pwPath, dotSSHPath, authKeysPath} {
		if err = os.Chown(f, uid, -1); err != nil {
			return fmt.Errorf("failed to chown %#q for user %#q: %w", f, u.Name, err)
		}
	}
	if u.Sudo != "" {
		if err := writeSudoers(u.Name, u.Sudo); err != nil {
			return fmt.Errorf("failed to write sudoers file for user %#q: %w", u.Name, err)
		}
	}
	return nil
}

View on GitHub (pinned to dd909d0973)

Solutions

  1. Check for a conflicting file at `<homedir>/.ssh` and remove it
  2. Verify disk space and writability of the home directory as root
  3. Read the wrapped errno in the error message to pinpoint the cause
  4. Delete and recreate the instance if prior partial provisioning left bad state

Example fix

// inside the VM, before reprovisioning
sudo rm -f /Users/alice/.ssh   # if it exists as a regular file
Defensive patterns

Strategy: validation

Validate before calling

sshDir := filepath.Join(home, ".ssh")
if st, err := os.Lstat(sshDir); err == nil && !st.IsDir() {
    return fmt.Errorf("%s exists and is not a directory; remove it first", sshDir)
}

Try / catch

if err := processUserData(ctx, data); err != nil {
    var pe *os.PathError
    if errors.As(err, &pe) && strings.Contains(err.Error(), ".ssh directory") {
        log.Printf("mkdir %s failed: %v", pe.Path, pe.Err)
    }
}

Prevention

When it happens

Trigger: os.MkdirAll(homedir/.ssh, 0o700) fails in createUser during processUserData on a darwin guest. Causes: home path is a file instead of a directory, parent not writable, ENOSPC, or read-only filesystem.

Common situations: A stale file named `.ssh` exists at the home path from a previous provisioning attempt; the custom `home` from user-data points into a read-only or restricted location; disk image full.

Related errors


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