yorukot/superfile · error
failed to remove source after copy: %w
Error message
failed to remove source after copy: %w
What it means
After copyElement succeeds, moveElement removes the original with os.RemoveAll(src); this error wraps a failure of that removal. At this point the data is already copied — the destination is safe — but the source could not be deleted, so the move is incomplete and a duplicate remains.
Source
Thrown at src/internal/file_operations.go:71
}
// If on the same partition, attempt to rename (which will use the same inode)
if sameDev {
if err = os.Rename(src, dst); err == nil {
return nil
}
// If rename fails, fall back to copy+delete
}
// 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)
}
View on GitHub (pinned to b72f550bc6)
Solutions
- Free/fix permissions on the source tree (chmod u+w, correct ownership) and delete it manually.
- Close processes holding files in the source (on Windows, check locks).
- Since the copy already succeeded, manually remove the leftover source with rm -rf after verifying the destination.
- Retry the move after resolving the lock; or treat it as a copy and clean up yourself.
Example fix
// before chmod 555 /data/src // removal fails after copy // after chmod -R u+w /data/src && rm -rf /data/src
Defensive patterns
Strategy: fallback
Validate before calling
// ensure every entry in src is deletable before the move
err := filepath.WalkDir(src, func(p string, d fs.DirEntry, err error) error {
if err != nil { return err }
if !d.IsDir() {
if info, _ := d.Info(); info != nil && info.Mode().Perm()&0200 == 0 {
return fmt.Errorf("read-only file blocks removal: %s", p)
}
}
return nil
}) Type guard
func sourceStillExists(src string) bool {
_, err := os.Stat(src)
return err == nil
} Try / catch
if err := moveElement(src, dst); err != nil {
if strings.Contains(err.Error(), "failed to remove source after copy") {
log.Warnf("Copy succeeded; leftover source at %s — clean up manually", src)
// data is safe at dst
return nil
}
return err
} Prevention
- Ensure source files are owner-writable before initiating a move.
- On Windows, avoid moving trees with files open in other applications.
- After a partial move, verify dst contents before deleting leftovers.
- Run moves as a user with delete permission over the whole source tree.
When it happens
Trigger: moveElement's copy phase succeeded but os.RemoveAll(src) fails: a file inside the source tree became read-only/owned by another user, a file was locked (Windows), or a new file appeared with no delete permission.
Common situations: Windows antivirus or another process holding the source open; source directory containing files owned by root; source files with permission 444/555; source modified concurrently during the copy.
Related errors
- failed to check partitions: %w
- failed to copy: %w
- failed to create destination directory: %w
- failed to read source directory: %w
- failed to create destination file: %w
AI-assisted analysis of yorukot/superfile@b72f550bc6 (2026-09-01).
Data as JSON: /api/errors/4a9e00cee8f000c0.
Report an issue: GitHub.