{"record":{"id":"f1ac41a5843f6da8","repo":"hashicorp/nomad","slug":"couldn-t-read-directory-v-w","errorCode":null,"errorMessage":"Couldn't read directory %v: %w","messagePattern":"Couldn't read directory (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/allocdir/task_dir.go","lineNumber":265,"sourceCode":"\t\t\tuid, gid := getOwner(s)\n\t\t\tif err := linkOrCopy(source, taskEntry, uid, gid, s.Mode().Perm()); err != nil {\n\t\t\t\treturn err\n\t\t\t}\n\n\t\t\tcontinue\n\t\t}\n\n\t\t// Create destination directory.\n\t\tdestDir := filepath.Join(t.Dir, dest)\n\n\t\tif err := createDir(t.Dir, dest); err != nil {\n\t\t\treturn fmt.Errorf(\"Couldn't create destination directory %v: %w\", destDir, err)\n\t\t}\n\n\t\t// Enumerate the files in source.\n\t\tdirEntries, err := os.ReadDir(source)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"Couldn't read directory %v: %w\", source, err)\n\t\t}\n\n\t\tfor _, fileEntry := range dirEntries {\n\t\t\tentry, err := fileEntry.Info()\n\t\t\tif err != nil {\n\t\t\t\treturn fmt.Errorf(\"Couldn't read the file information %v: %w\", entry, err)\n\t\t\t}\n\t\t\thostEntry := filepath.Join(source, entry.Name())\n\t\t\ttaskEntry := filepath.Join(destDir, filepath.Base(hostEntry))\n\t\t\tif entry.IsDir() {\n\t\t\t\tsubdirs[hostEntry] = filepath.Join(dest, filepath.Base(hostEntry))\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Check if entry exists. This can happen if restarting a failed\n\t\t\t// task.\n\t\t\tif _, err := os.Lstat(taskEntry); err == nil {\n\t\t\t\tcontinue","sourceCodeStart":247,"sourceCodeEnd":283,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/allocdir/task_dir.go#L247-L283","documentation":"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.","triggerScenarios":"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.","commonSituations":"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).","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)"],"exampleFix":"# before\nCouldn't read directory /etc/consul: open /etc/consul: no such file or directory\n# after\n$ sudo mkdir -p /etc/consul && sudo chmod 755 /etc/consul\n$ nomad alloc restart <alloc>","handlingStrategy":"validation","validationCode":"// verify every chroot source dir is readable just before Build\nfor source := range chrootMap {\n    if fi, err := os.Stat(source); err == nil && fi.IsDir() {\n        if _, err := os.ReadDir(source); err != nil {\n            return fmt.Errorf(\"chroot source %q unreadable: %w\", source, err)\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"if err := taskDir.Build(fsi, chroot, username); err != nil {\n    if strings.Contains(err.Error(), \"Couldn't read directory\") {\n        // restore/re-permission the host source dir, then retry the alloc\n        return retryBuildAfterFix()\n    }\n    return err\n}","preventionTips":["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"],"tags":["filesystem","chroot","read-dir"],"backgroundTag":"directory-read-failed","analyzedSha":"482b49bf1aec006f089bcfc7e632d8f6ac303e5e","analyzedAt":"2026-09-04T07:54:14.808Z","contentChangedAt":"2026-09-04T07:54:14.808Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}