lima-vm/lima · error

failed to write authorized_keys file for user %#q: %w

Error message

failed to write authorized_keys file for user %#q: %w

What it means

Writing the `authorized_keys` file (`<homedir>/.ssh/authorized_keys`, mode 0600) failed after the `.ssh` directory was created successfully. Without this file SSH public-key login for the user cannot work, so provisioning aborts. The wrapped os.WriteFile error carries the actual cause.

Source

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

	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
}

// writeSudoers appends a sudoers entry for the given user.
// writeSudoers is expected be called only once on creating the user account.
func writeSudoers(userName, sudo string) error {
	if strings.Contains(sudo, "\n") {

View on GitHub (pinned to dd909d0973)

Solutions

  1. Check guest disk space and free space if needed
  2. Verify `<homedir>/.ssh` exists as a writable directory (mode 0700)
  3. Inspect the wrapped errno (EACCES/ENOSPC/EIO) in the log
  4. Re-run provisioning after fixing; keys come from the user-data `users[].ssh_authorized_keys` field

Example fix

// before: instance disk full
limactl disk resize / grow instance disk
// after: reprovision
limactl start instance.yaml
Defensive patterns

Strategy: validation

Validate before calling

dotSSH := filepath.Join(home, ".ssh")
st, err := os.Stat(dotSSH)
if err != nil || !st.IsDir() || st.Mode().Perm()&0o200 == 0 {
    return fmt.Errorf("%s must exist as a writable directory", dotSSH)
}

Try / catch

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

Prevention

When it happens

Trigger: os.WriteFile(authKeysPath, joined SSH keys, 0o600) fails in createUser during processUserData. Causes: ENOSPC, EACCES on the just-created directory, I/O errors, or security software blocking writes into .ssh.

Common situations: Disk-full VM during heavy provisioning; EDR/antivirus on macOS guest restricting .ssh writes; extremely long ssh key lists hitting quota/limits.

Understand the failure class

Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.

Related errors


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