{"record":{"id":"48449358fc2a2617","repo":"hashicorp/nomad","slug":"couldn-t-open-src-file-v-w","errorCode":null,"errorMessage":"Couldn't open src file %v: %w","messagePattern":"Couldn't open src file (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/allocdir/alloc_dir.go","lineNumber":568,"sourceCode":"\t}()\n\n\t// Get the path relative to the alloc directory\n\twatcher := getFileWatcher(sanitizedPath)\n\treturn watcher.ChangeEvents(t, curOffset)\n}\n\n// getFileWatcher returns a FileWatcher for the given path.\nfunc getFileWatcher(path string) watch.FileWatcher {\n\treturn watch.NewPollingFileWatcher(path)\n}\n\n// fileCopy from src to dst setting the permissions and owner (if uid & gid are\n// both greater than 0)\nfunc fileCopy(src, dst string, uid, gid int, perm os.FileMode) error {\n\t// Do a simple copy.\n\tsrcFile, err := os.Open(src)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Couldn't open src file %v: %w\", src, err)\n\t}\n\tdefer srcFile.Close()\n\n\tdstFile, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE, perm)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"Couldn't create destination file %v: %w\", dst, err)\n\t}\n\tdefer dstFile.Close()\n\n\tif _, err := io.Copy(dstFile, srcFile); err != nil {\n\t\treturn fmt.Errorf(\"Couldn't copy %q to %q: %w\", src, dst, err)\n\t}\n\n\tif uid != idUnsupported && gid != idUnsupported {\n\t\tif err := dstFile.Chown(uid, gid); err != nil {\n\t\t\treturn fmt.Errorf(\"Couldn't copy %q to %q: %w\", src, dst, err)\n\t\t}\n\t}","sourceCodeStart":550,"sourceCodeEnd":586,"githubUrl":"https://github.com/hashicorp/nomad/blob/482b49bf1aec006f089bcfc7e632d8f6ac303e5e/client/allocdir/alloc_dir.go#L550-L586","documentation":"fileCopy() (used by linkOrCopy when hard links/symlinks are not possible) opens the source file before copying. If os.Open(src) fails the error is wrapped as \"Couldn't open src file\". It means the artifact/task source file could not be opened for reading.","triggerScenarios":"linkOrCopy falls back to fileCopy and the source path does not exist, is a directory, or is unreadable due to permissions during directory tree construction (e.g. copying chroot or shared artifacts).","commonSituations":"Missing or renamed source file in the alloc/shared tree; permission mismatch after chown/chmod changes; source removed by concurrent cleanup while a task dir is being built.","solutions":["Verify the source file exists and is readable by the nomad process before building the task dir","Fix permissions/ownership on the source file","Check for concurrent deletion of the source and serialize setup","Inspect the wrapped OS error (ENOENT vs EACCES vs EISDIR) to target the fix"],"exampleFix":"// before\nfileCopy(\"/missing/artifact\", dst, uid, gid, perm)\n// after\nif _, err := os.Stat(\"/path/to/artifact\"); err != nil {\n    return fmt.Errorf(\"artifact missing: %w\", err)\n}\nfileCopy(\"/path/to/artifact\", dst, uid, gid, perm)","handlingStrategy":"try-catch","validationCode":"if fi, err := os.Stat(src); err != nil || fi.IsDir() {\n    return fmt.Errorf(\"src not readable file: %q\", src)\n}\nif f, err := os.Open(src); err != nil {\n    return fmt.Errorf(\"src open failed: %w\", err)\n} else {\n    f.Close()\n}","typeGuard":null,"tryCatchPattern":"if err := linkOrCopy(src, dst, uid, gid, perm); err != nil {\n    if errors.Is(err, fs.ErrNotExist) {\n        // recreate or re-fetch the missing source before retry\n    }\n    return err\n}","preventionTips":["Verify source existence/permissions before building the task dir","Avoid concurrent cleanup racing directory construction","Check ownership after chown/chmod operations","Distinguish ENOENT vs EACCES from the wrapped OS error"],"tags":["filesystem","file-copy","permissions"],"backgroundTag":"file-open-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"}