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

  1. Check for disk/I/O errors (dmesg, smart status) since close is when write-back errors surface
  2. Ensure you do not close the underlying *os.File yourself before calling the library's Close
  3. 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

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


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)