hashicorp/nomad · error

error creating directory: %w

Error message

error creating directory: %w

What it means

This error wraps the failure of os.MkdirAll when a host volume plugin's Create operation tries to create the requested directory on the client. It means the directory could not be created at the requested path with the requested mode — the wrapped cause (permission denied, path exists as a file, nonexistent parent, full disk, etc.) is included via %w. Nomad logs the raw error and returns this wrapped error to the caller (the host volume manager), which surfaces it in the volume create RPC result.

Source

Thrown at client/hostvolumemanager/host_volume_plugin.go:136

	if _, err := os.Stat(path); err == nil {
		// already exists
		return resp, nil
	} else if !os.IsNotExist(err) {
		// doesn't exist, but some other path error
		log.Error("error with path", "error", err)
		return nil, err
	}

	params, err := decodeMkdirParams(req.Parameters)
	if err != nil {
		log.Error("error with parameters", "error", err)
		return nil, err
	}

	err = os.MkdirAll(path, params.Mode)
	if err != nil {
		log.Error("error creating directory", "error", err)
		return nil, fmt.Errorf("error creating directory: %w", err)
	}

	// os.MkdirAll perms are applied after umask, so the new directory may not
	// have the exact permissions requested.
	err = os.Chmod(path, params.Mode)
	if err != nil {
		log.Error("error setting directory permission mode", "error", err)
		return nil, fmt.Errorf("error setting directory permission mode: %w", err)
	}

	if runtime.GOOS != "windows" {
		// Chown note: A uid or gid of -1 means to not change that value.
		if err = os.Chown(path, params.Uid, params.Gid); err != nil {
			log.Error("error changing owner/group", "error", err, "uid", params.Uid, "gid", params.Gid)

			// Failing to change ownership is fatal for this plugin. Since we have
			// already created the directory, we should attempt to clean it.
			// Otherwise, the operator must do this manually.

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Check the wrapped cause (errors.Unwrap / %v of err) and fix the underlying OS problem — most often chown/chmod the parent directory so the nomad client user can create the path.
  2. Verify no regular file occupies the requested path (ls -l the path; remove or choose a different path).
  3. Confirm the parent directory chain exists and is on a writable filesystem (not read-only mount, not full disk: df, mount).
  4. If SELinux/AppArmor is enforcing, add appropriate policy or choose another path.

Example fix

// before: plugin fails because client user cannot write to parent
params := api.HostVolumeCreateParams{ Path: "/volumes/teamdata", Mode: 0o755 }

// after: pre-create and own the parent as an operator
// sudo mkdir -p /volumes && sudo chown nomad:nomad /volumes
params := api.HostVolumeCreateParams{ Path: "/volumes/teamdata", Mode: 0o755 }
Defensive patterns

Strategy: validation

Validate before calling

import "os"

func canCreateDir(path string) error {
    if fi, err := os.Lstat(path); err == nil && !fi.IsDir() {
        return fmt.Errorf("%s exists and is not a directory", path)
    }
    parent := filepath.Dir(path)
    if fi, err := os.Stat(parent); err != nil || !fi.IsDir() {
        return fmt.Errorf("parent %s missing or not a directory", parent)
    }
    f, err := os.CreateTemp(parent, ".wtest*")
    if err != nil {
        return fmt.Errorf("no write permission in %s: %w", parent, err)
    }
    f.Close(); os.Remove(f.Name())
    return nil
}

Try / catch

var hvErr *hvapi.Error
if errors.As(err, &hvErr) && strings.Contains(hvErr.Error(), "error creating directory") {
    var pathErr *os.PathError
    if errors.As(errors.Unwrap(err), &pathErr) && errors.Is(pathErr.Err, fs.ErrPermission) {
        // escalate to operator: fix ownership/permissions of parent
    }
}

Prevention

When it happens

Trigger: Calling the plugin Create operation (HostVolumePlugin.Create, reached via client host volume manager) where os.MkdirAll(path, params.Mode) fails: parent directory missing and cannot be created, permission denied on the target path, a non-directory file already exists at path, path is invalid/too long, or the filesystem is read-only or full.

Common situations: Operator submits a host volume create request with a path under a directory the nomad client user cannot write to (e.g. /var/lib/volumes owned by root); a regular file already exists at the requested path; the volume path points to a read-only mount or NFS export without write access; SELinux/AppArmor blocking mkdir.

Understand the failure class

Background: mkdir permission denied (EACCES): failed to create directory errors explained — this error's family across 32 libraries.

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/370b732ffd094abe. Report an issue: GitHub.