yorukot/superfile · error

failed to read source directory: %w

Error message

failed to read source directory: %w

What it means

After creating the destination directory, copyDir reads the source's entries with os.ReadDir(src); failure is wrapped as 'failed to read source directory'. This means the source directory exists (it was stat'd) but cannot be listed — typically a permissions problem or it being replaced by a non-directory mid-operation.

Source

Thrown at src/internal/file_operations.go:99

		return fmt.Errorf("failed to stat source: %w", err)
	}

	if srcInfo.IsDir() {
		return copyDir(src, dst, srcInfo)
	}
	return copyFile(src, dst, srcInfo)
}

// 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

View on GitHub (pinned to b72f550bc6)

Solutions

  1. Grant read permission on the source directory (chmod o+r / correct owner).
  2. Reconnect or remount the source volume if it dropped.
  3. Check the source is still a directory (concurrent modification) and retry.
  4. Copy with elevated privileges if system-level protection is intentional.

Example fix

// before
drwx------ root root /data/secret   // ReadDir fails as non-root
// after
chmod o+rx /data/secret
// then retry the copy
Defensive patterns

Strategy: validation

Validate before calling

st, err := os.Stat(src)
if err != nil { return err }
if !st.IsDir() { return fmt.Errorf("%s is not a directory", src) }
probe, err := os.ReadDir(src) // cheap pre-check of readability
if err != nil { return fmt.Errorf("source not readable: %w", err) }

Type guard

func dirReadable(src string) bool {
    _, err := os.ReadDir(src)
    return err == nil
}

Try / catch

if err := copyElement(src, dst); err != nil {
    var pErr *fs.PathError
    if errors.As(err, &pErr) && errors.Is(pErr.Err, fs.ErrPermission) {
        log.Errorf("Source dir %s unreadable — check permissions/mount", pErr.Path)
        return err // or skip-and-report in batch copy
    }
    return err
}

Prevention

When it happens

Trigger: copyElement -> copyDir where os.ReadDir(src) fails: no read permission on the directory, src is on an inaccessible mount, or src was swapped/removed concurrently after os.Stat.

Common situations: Copying a directory with mode 700 owned by another user; reading from a USB/network mount that dropped; racing deletion of the source tree during a paste; encrypted/protected directories.

Understand the failure class

Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.

Related errors


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