lima-vm/lima · error

failed to create /etc/sudoers.d directory: %w

Error message

failed to create /etc/sudoers.d directory: %w

What it means

os.MkdirAll("/etc/sudoers.d", 0o700) failed while preparing to append the user's sudoers entry. On a healthy macOS guest this directory normally exists; failure indicates the root filesystem is not writable by the agent or an unusual system state. The user's sudo setup is aborted.

Source

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

			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") {
		return errors.New("sudo field must not contain newline characters")
	}
	if err := os.MkdirAll("/etc/sudoers.d", 0o700); err != nil {
		return fmt.Errorf("failed to create /etc/sudoers.d directory: %w", err)
	}
	sudoersPath := "/etc/sudoers.d/90-cloud-init-users"
	f, err := os.OpenFile(sudoersPath, os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o400)
	if err != nil {
		return fmt.Errorf("failed to open sudoers file %#q: %w", sudoersPath, err)
	}
	if _, err = fmt.Fprintf(f, "%s %s\n", userName, sudo); err != nil {
		_ = f.Close()
		return fmt.Errorf("failed to write to sudoers file %#q for user %#q: %w", sudoersPath, userName, err)
	}
	return f.Close()
}

func writeFiles(ctx context.Context, entry cloudinittypes.WriteFile) error {
	if entry.Path == "" {
		return errors.New("path is required for write_files entry")
	}
	perm := os.FileMode(0o644)

View on GitHub (pinned to dd909d0973)

Solutions

  1. Ensure the Lima guestagent runs as root inside the VM
  2. Check the root volume is writable (`touch /etc/test`)
  3. Verify /etc/sudoers.d is a directory, not a regular file; fix or recreate the instance
  4. Free disk space if the wrapped error is ENOSPC

Example fix

// inside the VM (recovery)
sudo rm -f /etc/sudoers.d        # only if it is a regular file
sudo mkdir -p /etc/sudoers.d && sudo chmod 700 /etc/sudoers.d
Defensive patterns

Strategy: validation

Validate before calling

if fi, err := os.Lstat("/etc/sudoers.d"); err == nil && !fi.IsDir() {
    return errors.New("/etc/sudoers.d exists but is not a directory")
}
if err := os.MkdirAll("/etc/sudoers.d", 0o700); err != nil {
    return fmt.Errorf("/etc/sudoers.d not preparable: %w", err)
}

Try / catch

if err := processUserData(ctx, data); err != nil {
    var pe *os.PathError
    if errors.As(err, &pe) && strings.Contains(err.Error(), "sudoers.d directory") {
        log.Printf("cannot prepare %s: %v — check root privileges and writable /etc", pe.Path, pe.Err)
    }
}

Prevention

When it happens

Trigger: writeSudoers runs (user has a `sudo` field) and creating /etc/sudoers.d fails: read-only root volume, EPERM because the guestagent is not root, or /etc/sudoers.d exists as a regular file.

Common situations: Running the guestagent unprivileged in custom setups; sealed/system read-only volume configurations; a previous provisioning step replaced /etc/sudoers.d with a file; full disk (ENOSPC).

Related errors


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