yorukot/superfile · error

failed to stat source

Error message

failed to stat source: %w

What it means

copyElement starts by calling os.Stat(src) to learn whether the source is a file or directory; any Stat failure is wrapped as 'failed to stat source'. It means the source path does not exist or is inaccessible before any copying begins.

Solutions

  1. Verify the source path exists (ls / os.Stat) before calling the move/copy API.
  2. Fix parent directory permissions so the path is traversable.
  3. If the source was a broken symlink, remove it or point it at a real target.
  4. Retry if this was a transient race; serialize concurrent operations on the same tree.

Example fix

// before
if _, err := os.Stat(src); err != nil { return } // not checked by caller
// after
if _, err := os.Stat(src); err == nil {
    moveElement(src, dst)
}
Defensive patterns

Strategy: validation

Validate before calling

srcInfo, err := os.Stat(src)
if err != nil {
    return fmt.Errorf("refusing to copy: source %q unavailable: %w", src, err)
}
_ = srcInfo // safe to proceed to copyElement

Type guard

func sourceReady(src string) bool {
    st, err := os.Stat(src)
    return err == nil && (st.Mode().Perm()&0444 != 0 || st.IsDir())
}

Try / catch

if err := copyElement(src, dst); err != nil {
    var pErr *fs.PathError
    if errors.As(err, &pErr) && errors.Is(pErr.Err, fs.ErrNotExist) {
        log.Errorf("Source vanished: %s", pErr.Path)
        return fs.ErrNotExist // skip gracefully instead of failing the batch
    }
    return err
}

Prevention

When it happens

Trigger: moveElement -> copyElement where src was deleted/moved between the partition check and the copy, or src never existed / lacks parent-directory execute permission.

Common situations: Race where another process removed the source during the move; symlink to a nonexistent target; path typo; running without traverse permission on a parent directory.

Related errors


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

Appendix: source

Thrown at src/internal/file_operations.go:81

	// If on different partitions or rename failed, fall back to copy+delete
	err = copyElement(src, dst)
	if err != nil {
		return fmt.Errorf("failed to copy: %w", err)
	}

	err = os.RemoveAll(src)
	if err != nil {
		return fmt.Errorf("failed to remove source after copy: %w", err)
	}

	return nil
}

// copyElement handles copying of both files and directories
func copyElement(src, dst string) error {
	srcInfo, err := os.Stat(src)
	if err != nil {
		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)

View on GitHub (pinned to b72f550bc6)