hashicorp/nomad · error
Couldn't open src file %v: %w
Error message
Couldn't open src file %v: %w
What it means
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.
Source
Thrown at client/allocdir/alloc_dir.go:568
}()
// Get the path relative to the alloc directory
watcher := getFileWatcher(sanitizedPath)
return watcher.ChangeEvents(t, curOffset)
}
// getFileWatcher returns a FileWatcher for the given path.
func getFileWatcher(path string) watch.FileWatcher {
return watch.NewPollingFileWatcher(path)
}
// fileCopy from src to dst setting the permissions and owner (if uid & gid are
// both greater than 0)
func fileCopy(src, dst string, uid, gid int, perm os.FileMode) error {
// Do a simple copy.
srcFile, err := os.Open(src)
if err != nil {
return fmt.Errorf("Couldn't open src file %v: %w", src, err)
}
defer srcFile.Close()
dstFile, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE, perm)
if err != nil {
return fmt.Errorf("Couldn't create destination file %v: %w", dst, err)
}
defer dstFile.Close()
if _, err := io.Copy(dstFile, srcFile); err != nil {
return fmt.Errorf("Couldn't copy %q to %q: %w", src, dst, err)
}
if uid != idUnsupported && gid != idUnsupported {
if err := dstFile.Chown(uid, gid); err != nil {
return fmt.Errorf("Couldn't copy %q to %q: %w", src, dst, err)
}
}View on GitHub (pinned to 482b49bf1a)
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
Example fix
// before
fileCopy("/missing/artifact", dst, uid, gid, perm)
// after
if _, err := os.Stat("/path/to/artifact"); err != nil {
return fmt.Errorf("artifact missing: %w", err)
}
fileCopy("/path/to/artifact", dst, uid, gid, perm) Defensive patterns
Strategy: try-catch
Validate before calling
if fi, err := os.Stat(src); err != nil || fi.IsDir() {
return fmt.Errorf("src not readable file: %q", src)
}
if f, err := os.Open(src); err != nil {
return fmt.Errorf("src open failed: %w", err)
} else {
f.Close()
} Try / catch
if err := linkOrCopy(src, dst, uid, gid, perm); err != nil {
if errors.Is(err, fs.ErrNotExist) {
// recreate or re-fetch the missing source before retry
}
return err
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
Background: "open() failed", "failed to open file", "cannot create file" — what a file open error means and how to fix it — this error's family across 42 libraries.
Related errors
- Couldn't create destination file %v: %w
- plugin not executable
- failed to snapshot %s: %w
- error creating task %q dir: %w
- Chmod(%v) failed: %w
AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04).
Data as JSON: /api/errors/48449358fc2a2617.
Report an issue: GitHub.