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
- Ensure the Lima guestagent runs as root inside the VM
- Check the root volume is writable (`touch /etc/test`)
- Verify /etc/sudoers.d is a directory, not a regular file; fix or recreate the instance
- 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
- Ensure the guestagent runs as root
- Keep the root volume writable and non-full
- Confirm /etc/sudoers.d is a directory before reprovisioning
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
- failed to open sudoers file %#q: %w
- failed to write to sudoers file %#q for user %#q: %w
- failed to create parent directory for path %#q: %w
- failed to create temp file: %w
- failed to write temp plist: %w
AI-assisted analysis of lima-vm/lima@dd909d0973 (2026-09-01).
Data as JSON: /api/errors/ce3fd2af8138a75e.
Report an issue: GitHub.