hashicorp/nomad · error
Couldn't read directory %v: %w
Error message
Couldn't read directory %v: %w
What it means
After creating the destination directory for a chroot directory entry, embedDirs enumerates the source host directory with os.ReadDir(source). This error wraps ReadDir's failure for the host source path. It means Nomad could not list the host directory it intends to copy into the chroot.
Source
Thrown at client/allocdir/task_dir.go:265
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)
}
// Enumerate the files in source.
dirEntries, err := os.ReadDir(source)
if err != nil {
return fmt.Errorf("Couldn't read directory %v: %w", source, err)
}
for _, fileEntry := range dirEntries {
entry, err := fileEntry.Info()
if err != nil {
return fmt.Errorf("Couldn't read the file information %v: %w", entry, err)
}
hostEntry := filepath.Join(source, entry.Name())
taskEntry := filepath.Join(destDir, filepath.Base(hostEntry))
if entry.IsDir() {
subdirs[hostEntry] = filepath.Join(dest, filepath.Base(hostEntry))
continue
}
// Check if entry exists. This can happen if restarting a failed
// task.
if _, err := os.Lstat(taskEntry); err == nil {
continueView on GitHub (pinned to 482b49bf1a)
Solutions
- Check the wrapped errno: EACCES → `chmod/chown` the source dir readable by the nomad user; ENOENT → restore the missing host directory (e.g. reinstall the package providing it)
- Identify what deletes the source dir (temp cleaners, config management) and exclude it
- Rerun the alloc after restoring the source; chroot entries missing at stat time are skipped silently, so this usually means it existed and vanished
- Verify no mount under the source path dropped (dmesg, `mount` output)
Example fix
# before Couldn't read directory /etc/consul: open /etc/consul: no such file or directory # after $ sudo mkdir -p /etc/consul && sudo chmod 755 /etc/consul $ nomad alloc restart <alloc>
Defensive patterns
Strategy: validation
Validate before calling
// verify every chroot source dir is readable just before Build
for source := range chrootMap {
if fi, err := os.Stat(source); err == nil && fi.IsDir() {
if _, err := os.ReadDir(source); err != nil {
return fmt.Errorf("chroot source %q unreadable: %w", source, err)
}
}
} Try / catch
if err := taskDir.Build(fsi, chroot, username); err != nil {
if strings.Contains(err.Error(), "Couldn't read directory") {
// restore/re-permission the host source dir, then retry the alloc
return retryBuildAfterFix()
}
return err
} Prevention
- Exclude chroot source dirs from aggressive tmp-cleaners and config-management pruning
- Ensure the nomad user can read all chroot sources (755 typical)
- Keep chroot sources on local stable storage, not removable/network mounts
- Pin critical packages so sources don't vanish mid-upgrade
When it happens
Trigger: os.ReadDir(source) fails while embedding a directory chroot entry — source existed at os.Stat time but was removed/renamed before listing, or is unreadable (EACCES) to the nomad user.
Common situations: TOCTOU race: another process (config management, tmp cleaner) removed the source dir between stat and readdir; permissions tightened on host dirs like /etc or /usr; source is on a mount that went away (network filesystem).
Related errors
- Failed to mount shared directory for task: %w
- Couldn't create destination directory %v: %w
- Couldn't read the file information %v: %w
- Couldn't resolve symlink for %v: %w
- Couldn't create symlink: %w
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/f1ac41a5843f6da8.
Report an issue: GitHub.