lima-vm/lima · error
failed to read boot scripts directory %#q: %w
Error message
failed to read boot scripts directory %#q: %w
What it means
runBootScripts enumerates per-once and per-boot script directories (cloud-init style, e.g. /var/lib/cloud/scripts/per-boot) with os.ReadDir. If a directory cannot be read, provisioning fails with this wrapped error instead of continuing. This typically means the directory is missing or unreadable.
Source
Thrown at pkg/guestagent/fakecloudinit/fakecloudinit_darwin.go:386
// FIXME: avoid hardcoding the primary network name
const primaryNetwork = "Ethernet"
cmd := exec.CommandContext(ctx, "networksetup", append([]string{"-setdnsservers", primaryNetwork}, resolvConf.Nameservers...)...)
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)
}
return nil
}
func runBootScripts(ctx context.Context) error {
dirs := []string{
"/var/lib/cloud/scripts/per-boot",
}
var errs []error
for _, dir := range dirs {
dirEntries, err := os.ReadDir(dir)
if err != nil {
return fmt.Errorf("failed to read boot scripts directory %#q: %w", dir, err)
}
for _, entry := range dirEntries {
if entry.IsDir() {
continue
}
scriptPath := filepath.Join(dir, entry.Name())
// entry.Type().Mode() does not seem to contain permission bits
entryInfo, err := entry.Info()
if err != nil {
logrus.Warnf("Skipping boot script %#q due to stat error: %v", scriptPath, err)
continue
}
if entryInfo.Mode().Perm()&0o111 == 0 {
logrus.Warnf("Skipping non-executable boot script %#q (%v)", scriptPath, entryInfo.Mode().Perm())
continue
}
cmd := exec.CommandContext(ctx, scriptPath)
cmd.Stdout = os.StdoutView on GitHub (pinned to dd909d0973)
Solutions
- Create the missing directory in the guest (e.g. `sudo mkdir -p /var/lib/cloud/scripts/per-boot`).
- Make provisioning create the directories (os.MkdirAll) before runBootScripts reads them, or treat ENOENT as empty.
- Check the wrapped error: ENOENT means missing dir; EACCES means permission problem - fix ownership accordingly.
- Ensure no earlier user-data step removes or replaces /var/lib/cloud.
Example fix
// before
dirEntries, err := os.ReadDir(dir)
// after
if err := os.MkdirAll(dir, 0o755); err != nil { ... }
dirEntries, err := os.ReadDir(dir) Defensive patterns
Strategy: fallback
Validate before calling
for _, dir := range []string{"/var/lib/cloud/scripts/per-once", "/var/lib/cloud/scripts/per-boot"} {
if fi, err := os.Stat(dir); err != nil || !fi.IsDir() {
os.MkdirAll(dir, 0o755)
}
} Try / catch
if err := runBootScripts(ctx); err != nil {
var pe *fs.PathError
if errors.As(err, &pe) && errors.Is(pe.Err, syscall.ENOENT) {
// directory missing: create it or treat as no scripts
}
} Prevention
- Provision the cloud-init script directories before enabling boot scripts.
- Do not mount volumes over /var/lib/cloud.
- Treat a missing per-boot directory as an empty script set rather than a fatal error.
When it happens
Trigger: One of the boot-script directories (per-once or /var/lib/cloud/scripts/per-boot) does not exist on the macOS guest, is a file instead of a directory, or the process lacks read permission for it.
Common situations: Fresh macOS guest where the cloud-init directory layout was never created; a previous provisioning step deleted the directory; mounting a volume over /var/lib/cloud that hides the scripts dir.
Related errors
- failed to write file for path %#q: %w
- failed to create symlink from %#q to %#q: %w
- failed to write password file for user %#q: %w
- failed to create parent directory for path %#q: %w
- failed to create temp file: %w
AI-assisted analysis of lima-vm/lima@dd909d0973 (2026-09-01).
Data as JSON: /api/errors/4d270a68bd23c8cf.
Report an issue: GitHub.