hashicorp/nomad · error

error creating directory

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.

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.

Appendix: 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)