ipfs/kubo · warning
abort failed: close: %w, remove: %v
Error message
abort failed: close: %w, remove: %v
What it means
atomicfile.Abort wraps both errors from closing the temp file and removing it when neither succeeds. It reports the two underlying failures (%w preserves closeErr for errors.Is). Abort itself means the target file was never replaced.
Source
Thrown at repo/fsrepo/migrations/atomicfile/atomicfile.go:67
// Try to cleanup temp file, but prioritize close error
_ = os.Remove(f.File.Name())
return closeErr
}
if err := os.Rename(f.File.Name(), f.path); err != nil {
// The temporary file may hold sensitive data, do not leave it behind.
_ = os.Remove(f.File.Name())
return err
}
return nil
}
// Abort removes the temporary file without replacing the target
func (f *File) Abort() error {
closeErr := f.File.Close()
removeErr := os.Remove(f.File.Name())
if closeErr != nil && removeErr != nil {
return fmt.Errorf("abort failed: close: %w, remove: %v", closeErr, removeErr)
}
if closeErr != nil {
return closeErr
}
return removeErr
}
// ReadFrom reads from the given reader into the atomic file
func (f *File) ReadFrom(r io.Reader) (int64, error) {
return io.Copy(f.File, r)
}
View on GitHub (pinned to 329838acdf)
Solutions
- Call Abort only once and only when Commit was not called (Commit already closes the file)
- Check errors.Is(err, fs.ErrClosed) / permission errors on the temp dir and fix filesystem access
- If close failed only because the file was already closed, treat as cleanup already done
Example fix
// before
af.Abort()
af.Commit() // or vice versa
// after
if err := af.Commit(); err != nil {
af.Abort()
} Defensive patterns
Strategy: try-catch
Validate before calling
// ensure writable temp location before starting write
if st, err := os.Stat(os.TempDir()); err != nil || !st.IsDir() { /* fix TMPDIR */ } Try / catch
if err := af.Abort(); err != nil {
var pe *fs.PathError
if errors.Is(err, fs.ErrClosed) { /* already cleaned */ } else if errors.As(err, &pe) {
log.Warnf("abort cleanup incomplete: %v", pe)
}
} Prevention
- Call Abort exactly once, never after Commit
- Check TMPDIR writability before repo writes
- Clean up temp dirs when disk is near full
When it happens
Trigger: Calling Abort() on an already-closed *File (second Abort, or Abort after Commit/close) - Close fails and Remove fails because the name no longer exists on some systems or permissions block it; read-only temp directory; file deleted underneath.
Common situations: Error paths in config/migration save code that call both Commit-cleanup and Abort; disk full or permission problems in the repo directory; double-deferred cleanup in migrations.
Related errors
- failed to get temp dir: %s
- cannot read migration: %w
- %s path (%q) does not exist: %w
- unexpected error while checking writeablility of repo root:
- flushing %s: %w
AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03).
Data as JSON: /api/errors/1d45e4e148ee6dab.
Report an issue: GitHub.