Summary
Every error path in find_replace.go and file_handling.go calls log.Fatalf, which calls os.Exit(1). os.Exit does not run deferreds, so:
A single permission-denied os.ReadDir (e.g., a .cache subdir owned by another user) takes down the entire run, even though the rest of the tree could still be processed.
Impact (Reliability: High)
- Half-finished operations are unrecoverable — the user can't tell which subtree was processed and which wasn't.
- Even read-only failures (e.g., a single stat on a broken symlink) are fatal.
- Concurrent goroutines may be at any point in their pipeline when one dies, so files can be left as bare temp files or with mixed names.
Suggested Fix
- Stop calling
log.Fatal from anywhere except main.
- Bubble errors up via return values (or an
errgroup).
- Default policy: log the error, skip the failing entry, continue with the rest.
- Optional
--strict flag to abort on first error (after a clean shutdown).
main should exit non-zero if any error was encountered.
Files
- All
log.Fatal* sites in find_replace.go and file_handling.go
Summary
Every error path in
find_replace.goandfile_handling.gocallslog.Fatalf, which callsos.Exit(1).os.Exitdoes not run deferreds, so:Rename/Write.A single permission-denied
os.ReadDir(e.g., a.cachesubdir owned by another user) takes down the entire run, even though the rest of the tree could still be processed.Impact (Reliability: High)
Suggested Fix
log.Fatalfrom anywhere exceptmain.errgroup).--strictflag to abort on first error (after a clean shutdown).mainshould exit non-zero if any error was encountered.Files
log.Fatal*sites infind_replace.goandfile_handling.go