yorukot/superfile · error

failed to get entry info: %w

Error message

failed to get entry info: %w

What it means

copyDir wraps any error returned by os.DirEntry.Info() when it tries to stat an entry inside a directory being recursively copied. The underlying cause (permission, race where the file vanished, broken symlink handling) is preserved via %w. It aborts the recursive copy of the whole directory tree.

Source

Thrown at src/internal/file_operations.go:108

// copyDir recursively copies a directory
func copyDir(src, dst string, srcInfo os.FileInfo) error {
	err := os.MkdirAll(dst, srcInfo.Mode())
	if err != nil {
		return fmt.Errorf("failed to create destination directory: %w", err)
	}

	entries, err := os.ReadDir(src)
	if err != nil {
		return fmt.Errorf("failed to read source directory: %w", err)
	}

	for _, entry := range entries {
		srcPath := filepath.Join(src, entry.Name())
		dstPath := filepath.Join(dst, entry.Name())

		entryInfo, err := entry.Info()
		if err != nil {
			return fmt.Errorf("failed to get entry info: %w", err)
		}

		if entryInfo.IsDir() {
			err = copyDir(srcPath, dstPath, entryInfo)
		} else {
			err = copyFile(srcPath, dstPath, entryInfo)
		}
		if err != nil {
			return err
		}
	}
	return nil
}

// is an equivalent of "cp -P" command
func copyLinkFile(src, dst string) error {
	target, err := os.Readlink(src)
	if err != nil {

View on GitHub (pinned to b72f550bc6)

Solutions

  1. Re-run the copy operation; transient races usually disappear on a second attempt.
  2. Check read/execute permissions on the source directory tree (ls -la, or chmod to add r+x).
  3. Freeze or exclude concurrently-written directories (stop writers, skip build/log dirs) before copying.
  4. If files vanish regularly, wrap the copy in retry logic or copy a consistent snapshot.

Example fix

// before
err = copyDir(srcPath, dstPath, entryInfo)
// after
if err != nil {
    var pe *fs.PathError
    if errors.As(err, &pe) && errors.Is(pe.Err, syscall.ENOENT) {
        slog.Warn("entry vanished during copy, skipping", "path", srcPath)
        continue
    }
    return err
}
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-flight: ensure the tree is traversable
if info, err := os.Stat(srcDir); err != nil || !info.IsDir() {
    return fmt.Errorf("invalid source dir %s", srcDir)
}

Type guard

func isDirEntryStatable(e os.DirEntry) bool {
    _, err := e.Info()
    return err == nil
}

Try / catch

if err := ops.CopyElement(src, dst); err != nil {
    var pe *fs.PathError
    if errors.As(err, &pe) && errors.Is(pe.Err, syscall.ENOENT) {
        // entry vanished mid-copy: retry or skip
    } else {
        return err
    }
}

Prevention

When it happens

Trigger: Calling copyElement or copyDir on a directory whose contents change between os.ReadDir and entry.Info(), or where the process lacks permission to stat an entry (e.g. a directory requiring root traversal).

Common situations: Copying a directory being concurrently modified (build output, log dirs, /tmp churn); copying into a container mount where entries race; permission-restricted source directories.

Related errors


AI-assisted analysis of yorukot/superfile@b72f550bc6 (2026-09-01). Data as JSON: /api/errors/30cba63dfc205ace. Report an issue: GitHub.