kopia/kopia · warning
unable to close local file
Error message
unable to close local file
What it means
Close on a localfs file calls f.File.Close() and wraps any OS error as "unable to close local file". Even though close errors are often benign, the library surfaces them because a failed close can indicate flushed-write failures or descriptor exhaustion.
Solutions
- Check for disk/I/O errors (dmesg, smart status) since close is when write-back errors surface
- Ensure you do not close the underlying *os.File yourself before calling the library's Close
- Retry the operation; a transient network-mount error usually clears on remount
Example fix
// before f, _ := os.Open(p) f.Close() // double close entry.Close() // after f, _ := os.Open(p) entry.Close() // let the library own the handle
Defensive patterns
Strategy: try-catch
Try / catch
if err := f.Close(); err != nil {
log.Warnf("close failed (possible write-back error): %v", err)
// treat as non-fatal unless data integrity matters
} Prevention
- Let the library own file handles; never double-close the underlying *os.File
- Watch dmesg/disk health — close errors often reveal pending I/O failures
- Check fd usage if closing many files in a loop
When it happens
Trigger: Calling Close() on an opened local file when the OS returns an error from close(2) — delayed I/O errors on write-back, fd already closed, or filesystem going away.
Common situations: Disk full or I/O errors surfacing at close time on Linux, double-close after custom code already closed the handle, files on network mounts that dropped.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- can't close tmp file
- error closing cache marker file
- error closing index file
- can't close temporary file
- can't close temporary file
AI-assisted analysis of kopia/kopia@82495e54b5 (2026-09-07).
Data as JSON: /api/errors/3a8bc5bbb8ff2ad5.
Report an issue: GitHub.
Appendix: source
Thrown at fs/localfs/local_fs.go:136
if err != nil {
return nil, errors.Wrap(err, "unable to stat() local file")
}
basename, prefix := splitDirPrefix(f.Name())
return newFilesystemFile(newEntry(basename, fi, prefix, f.opts)), nil
}
func (f *fileWithMetadata) Close() error {
if f.opts.StreamingReads {
// HintNotNeeded is advisory and best-effort; failures don't affect
// correctness. The error is intentionally ignored and not logged given
// that Close() has no ctx to retrieve a ctx-derived logger.
_ = iomem.HintNotNeeded(f.File)
}
if err := f.File.Close(); err != nil {
return errors.Wrap(err, "unable to close local file")
}
return nil
}
func (fsf *filesystemFile) Open(ctx context.Context) (fs.Reader, error) {
f, err := os.Open(fsf.fullPath())
if err != nil {
return nil, errors.Wrap(err, "unable to open local file")
}
// In streaming-reads mode, hint the kernel for readahead at open
// (HintStreaming) and to drop the pages at close (HintNotNeeded).
if fsf.opts.StreamingReads {
if hintErr := iomem.HintStreaming(f); hintErr != nil {
log(ctx).Debugf("streaming read hint at open failed for %q: %v", f.Name(), hintErr)
}
}View on GitHub (pinned to 82495e54b5)