{"record":{"id":"3a8bc5bbb8ff2ad5","repo":"kopia/kopia","slug":"unable-to-close-local-file","errorCode":null,"errorMessage":"unable to close local file","messagePattern":"unable to close local file","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"fs/localfs/local_fs.go","lineNumber":136,"sourceCode":"\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"unable to stat() local file\")\n\t}\n\n\tbasename, prefix := splitDirPrefix(f.Name())\n\n\treturn newFilesystemFile(newEntry(basename, fi, prefix, f.opts)), nil\n}\n\nfunc (f *fileWithMetadata) Close() error {\n\tif f.opts.StreamingReads {\n\t\t// HintNotNeeded is advisory and best-effort; failures don't affect\n\t\t// correctness. The error is intentionally ignored and not logged given\n\t\t// that Close() has no ctx to retrieve a ctx-derived logger.\n\t\t_ = iomem.HintNotNeeded(f.File)\n\t}\n\n\tif err := f.File.Close(); err != nil {\n\t\treturn errors.Wrap(err, \"unable to close local file\")\n\t}\n\n\treturn nil\n}\n\nfunc (fsf *filesystemFile) Open(ctx context.Context) (fs.Reader, error) {\n\tf, err := os.Open(fsf.fullPath())\n\tif err != nil {\n\t\treturn nil, errors.Wrap(err, \"unable to open local file\")\n\t}\n\n\t// In streaming-reads mode, hint the kernel for readahead at open\n\t// (HintStreaming) and to drop the pages at close (HintNotNeeded).\n\tif fsf.opts.StreamingReads {\n\t\tif hintErr := iomem.HintStreaming(f); hintErr != nil {\n\t\t\tlog(ctx).Debugf(\"streaming read hint at open failed for %q: %v\", f.Name(), hintErr)\n\t\t}\n\t}","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/kopia/kopia/blob/82495e54b584c1ef6073c9e1be048f57f8aef078/fs/localfs/local_fs.go#L118-L154","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nf, _ := os.Open(p)\nf.Close()            // double close\nentry.Close()\n// after\nf, _ := os.Open(p)\nentry.Close()        // let the library own the handle","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := f.Close(); err != nil {\n    log.Warnf(\"close failed (possible write-back error): %v\", err)\n    // treat as non-fatal unless data integrity matters\n}","preventionTips":["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"],"tags":["file-close","io","localfs"],"backgroundTag":"file-write-failed","analyzedSha":"82495e54b584c1ef6073c9e1be048f57f8aef078","analyzedAt":"2026-09-07T20:35:21.689Z","contentChangedAt":"2026-09-07T20:35:21.689Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}