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

  1. Call Abort only once and only when Commit was not called (Commit already closes the file)
  2. Check errors.Is(err, fs.ErrClosed) / permission errors on the temp dir and fix filesystem access
  3. 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

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


AI-assisted analysis of ipfs/kubo@329838acdf (2026-09-03). Data as JSON: /api/errors/1d45e4e148ee6dab. Report an issue: GitHub.