kubernetes/kops · error

failed to ensure the directory: %s, error: %w

Error message

failed to ensure the directory: %s, error: %w

What it means

During the volume-mount phase of nodeup, Build() iterates NodeupConfig.VolumeMounts and, for each mount, ensures the target directory exists via b.EnsureDirectory before formatting/mounting the device. If directory creation fails (permissions, non-empty mountpoint conflicts, read-only root filesystem, I/O error), the error is wrapped as 'failed to ensure the directory'.

Source

Thrown at nodeup/pkg/model/volumes.go:49

	*NodeupModelContext
}

var _ fi.NodeupModelBuilder = &VolumesBuilder{}

// Build is responsible for handling the mounting additional volumes onto the instance
func (b *VolumesBuilder) Build(c *fi.NodeupModelBuilderContext) error {
	// @step: check if the instancegroup has any volumes to mount
	if !b.UseVolumeMounts() {
		klog.V(1).Info("Skipping the volume builder, no volumes defined for this instancegroup")

		return nil
	}

	// @step: iterate the volume mounts and attempt to mount the devices
	for _, x := range b.NodeupConfig.VolumeMounts {
		// @check the directory exists, else create it
		if err := b.EnsureDirectory(x.Path); err != nil {
			return fmt.Errorf("failed to ensure the directory: %s, error: %w", x.Path, err)
		}

		m := &mount.SafeFormatAndMount{
			Exec:      utilexec.New(),
			Interface: mount.New(""),
		}

		// @check if the device is already mounted
		if found, err := b.IsMounted(m, x.Device, x.Path); err != nil {
			return fmt.Errorf("failed to check if device %q is mounted, error: %w", x.Device, err)
		} else if found {
			klog.V(3).Infof("Skipping device: %s, path: %s as already mounted", x.Device, x.Path)
			continue
		}

		klog.Infof("Attempting to format and mount device: %s, path: %s", x.Device, x.Path)

		if err := m.FormatAndMount(x.Device, x.Path, x.Filesystem, x.MountOptions); err != nil {

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Check the wrapped inner error with `klog`/journalctl on the node (nodeup logs) to see the exact mkdir failure reason (EACCES/EROFS/EEXIST/ENOSPC).
  2. Remove or rename any non-directory file already existing at the VolumeMounts Path: `ls -la /path`, fix, then rerun nodeup.
  3. Free disk space or remount the root filesystem read-write if ENOSPC/EROFS is reported.
  4. Correct the volumeMounts path in the cluster spec so it points to a valid mountpoint location, then run `kops update cluster` and re-bootstrap the node.

Example fix

// before: path is an existing regular file, mkdir fails
volumeMounts:
- device: /dev/nvme1n1
  path: /data/file.txt
// after: point the mount at a directory
volumeMounts:
- device: /dev/nvme1n1
  path: /data
Defensive patterns

Strategy: validation

Validate before calling

// Before nodeup runs, on the node:
// test -e /data && [ ! -d /data ] && echo "CONFLICT: regular file at mount path"
os.Stat(path)
if err == nil && !info.IsDir() {
	return fmt.Errorf("volumeMounts path %s exists and is not a directory", path)
}
// also check writability of parent: os.WriteFile(dir+"/.w", nil, 0600)

Type guard

func isMountablePath(path string) error {
	if fi, err := os.Stat(path); err == nil && !fi.IsDir() {
		return fmt.Errorf("%s is a %v, not a directory", path, fi.Mode())
	}
	return nil
}

Try / catch

if err := b.EnsureDirectory(x.Path); err != nil {
	if errors.Is(err, os.ErrExist) || isReadOnlyFS(err) {
		klog.Errorf("cannot create mount dir %s: %v — fix node filesystem and retry", x.Path, err)
	}
	return fmt.Errorf("failed to ensure the directory: %s, error: %w", x.Path, err)
}

Prevention

When it happens

Trigger: NodeupConfig.VolumeMounts contains an entry whose Path cannot be created: EnsureDirectory returns an error (mkdir failed due to EACCES, EROFS, ENOSPC, or an existing non-directory file at that path).

Common situations: VolumeMounts path colliding with an existing regular file on the root filesystem; root disk full or read-only (e.g. immutable/scratch node images); SELinux/AppArmor or restricted container runtime denying mkdir; mistyped mount path such as a path under a directory that only appears after another mount.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/1b60092ec590b4a6. Report an issue: GitHub.