hashicorp/nomad · error

Couldn't create destination directory %v: %w

Error message

Couldn't create destination directory %v: %w

What it means

embedDirs, called from buildChroot, embeds host files into the chroot task directory. When a chroot mapping entry is a single file, it first creates the destination directory inside t.Dir via createDir. This error wraps createDir's failure, reported with the destination path. It aborts chroot construction for the alloc.

Source

Thrown at client/allocdir/task_dir.go:242

func (t *TaskDir) embedDirs(entries map[string]string) error {
	subdirs := make(map[string]string)
	for source, dest := range entries {
		if t.skip.Contains(source) {
			// source in skip list
			continue
		}

		// Check to see if directory exists on host.
		s, err := os.Stat(source)
		if os.IsNotExist(err) {
			continue
		}

		// Embedding a single file
		if !s.IsDir() {
			if err := createDir(t.Dir, filepath.Dir(dest)); err != nil {
				return fmt.Errorf("Couldn't create destination directory %v: %w", dest, err)
			}

			// Copy the file.
			taskEntry := filepath.Join(t.Dir, dest)
			uid, gid := getOwner(s)
			if err := linkOrCopy(source, taskEntry, uid, gid, s.Mode().Perm()); err != nil {
				return err
			}

			continue
		}

		// Create destination directory.
		destDir := filepath.Join(t.Dir, dest)

		if err := createDir(t.Dir, dest); err != nil {
			return fmt.Errorf("Couldn't create destination directory %v: %w", destDir, err)
		}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Read the wrapped OS error: EEXIST/ENOTDIR → delete the conflicting file at the destination inside the task dir; ENOSPC → free disk space; EACCES → fix data_dir ownership
  2. Clean the task dir for the failing alloc and restart it (`rm -rf <data_dir>/<alloc>/<task>` with client stopped)
  3. Check the task's chroot mapping in the client config for duplicate/conflicting destination paths
  4. Confirm the nomad user can write t.Dir

Example fix

# before
Couldn't create destination directory etc/ssl/certs: mkdir /var/nomad/.../etc/ssl/certs: not a directory
# after
$ ls -ld /var/nomad/<alloc>/<task>/etc/ssl/certs  # it's a file
$ rm /var/nomad/<alloc>/<task>/etc/ssl/certs
$ nomad alloc restart <alloc>
Defensive patterns

Strategy: validation

Validate before calling

// pre-check chroot destination inside task dir isn't occupied by a file
for _, dest := range chrootMap {
    p := filepath.Join(taskDir, filepath.Dir(dest))
    if fi, err := os.Stat(p); err == nil && !fi.IsDir() {
        os.RemoveAll(p) // or fail fast with a clear message
    }
}

Try / catch

if err := taskDir.Build(fsi, chroot, username); err != nil {
    var e *fmt.Errorf
    if errors.As(err, &e) && strings.Contains(err.Error(), "Couldn't create destination directory") {
        // inspect wrapped errno: ENOSPC → free space; ENOTDIR → clean task dir; then retry
        return retryAfterClean(taskDir, err)
    }
    return err
}

Prevention

When it happens

Trigger: TaskDir.buildChroot processing a chroot map entry whose source is a file, and createDir(t.Dir, filepath.Dir(dest)) fails — e.g. a non-directory exists at the parent path inside the task dir, or the task dir is unwritable.

Common situations: data_dir on a full/read-only disk; previous task run left a file where a chroot destination directory must be; chroot map entry with conflicting paths (same dest as both file and directory from config); permissions on the nomad data dir changed.

Related errors


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