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

  1. Verify the source file exists and is readable by the nomad process before building the task dir
  2. Fix permissions/ownership on the source file
  3. Check for concurrent deletion of the source and serialize setup
  4. 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

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


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