lima-vm/lima · error

failed to write file for path %#q: %w

Error message

failed to write file for path %#q: %w

What it means

Raised by processUserData when a `write_files:` entry from the user-data cannot be written. writeFiles validates the path and permissions, creates the parent directory, then writes the file; the wrapped error pinpoints which of those steps failed. The target path is included via %#q.

Source

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

	}
	for _, m := range userData.Mounts {
		if err = mountFSTabEntry(m); err != nil {
			errs = append(errs, fmt.Errorf("failed to mount fstab entry %v: %w", m, err))
		}
	}
	if userData.Timezone != "" {
		if err = setTimezone(ctx, userData.Timezone); err != nil {
			errs = append(errs, fmt.Errorf("failed to set timezone: %w", err))
		}
	}
	for _, u := range userData.Users {
		if err := createUser(ctx, &u); err != nil {
			errs = append(errs, fmt.Errorf("failed to create user %#q: %w", u.Name, err))
		}
	}
	for _, entry := range userData.WriteFiles {
		if err := writeFiles(ctx, entry); err != nil {
			errs = append(errs, fmt.Errorf("failed to write file for path %#q: %w", entry.Path, err))
		}
	}
	if userData.ManageResolvConf && userData.ResolvConf != nil {
		if err = setResolvConf(ctx, userData.ResolvConf); err != nil {
			errs = append(errs, fmt.Errorf("failed to apply DNS configuration: %w", err))
		}
	}
	if userData.CACerts != nil {
		logrus.Warn("ca_certs is not implemented")
	}
	if len(userData.BootCmd) > 0 {
		logrus.Warn("bootcmd is not implemented")
	}
	return errors.Join(errs...)
}

// mountFSTabEntry mounts a filesystem based on the given fstab entry.
// The format mimics Linux's convention.

View on GitHub (pinned to dd909d0973)

Solutions

  1. Read the wrapped error: it tells whether path, permissions, mkdir, write, or chown failed.
  2. Ensure each write_files entry has a non-empty absolute `path`.
  3. Specify permissions as an octal string like "0644", not symbolic.
  4. Check that the agent has write access to the destination directory.
  5. If `owner` is set, make sure the referenced user/group already exists before the write_files step.

Example fix

// before (user-data)
write_files:
  - content: "hello"
    path: /etc/motd
    permissions: "rw-r--r--"
// after
write_files:
  - content: "hello"
    path: /etc/motd
    permissions: "0644"
Defensive patterns

Strategy: validation

Validate before calling

func validateWriteFiles(entries []cloudinittypes.WriteFile) error {
  for i, e := range entries {
    if e.Path == "" || !filepath.IsAbs(e.Path) { return fmt.Errorf("write_files[%d]: path must be absolute", i) }
    if e.Permissions != "" {
      if _, err := strconv.ParseUint(e.Permissions, 8, 32); err != nil {
        return fmt.Errorf("write_files[%d]: permissions %q not octal", i, e.Permissions)
      }
    }
  }
  return nil
}

Type guard

func isWritableEntry(e cloudinittypes.WriteFile) bool {
  if e.Path == "" { return false }
  if e.Permissions != "" { _, err := strconv.ParseUint(e.Permissions, 8, 32); return err == nil }
  return true
}

Try / catch

for _, entry := range userData.WriteFiles {
  if err := writeFiles(ctx, entry); err != nil {
    log.Errorf("write_files failed for %q: %v", entry.Path, err)
  }
}

Prevention

When it happens

Trigger: An entry has empty `path`, a non-octal `permissions` string, the parent directory cannot be created (permission denied), the os.WriteFile itself fails, or the subsequent `chown <owner>` command fails when `owner` is set.

Common situations: Writing to a root-only location while running unprivileged, typo in the permissions (e.g. `rwxr-xr-x` instead of `0755`), or an owner spec that the chown command does not accept (user must exist).

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/c771c29653cc783b. Report an issue: GitHub.