{"record":{"id":"bc873fe7de25e00b","repo":"benbjohnson/litestream","slug":"close-l0-file-w","errorCode":null,"errorMessage":"close L0 file: %w","messagePattern":"close L0 file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"db.go","lineNumber":1652,"sourceCode":"\n\ttmpFile, err := os.Create(tmpPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"create temp L0 file: %w\", err)\n\t}\n\tdefer func() { _ = os.Remove(tmpPath) }() // Clean up temp file on error\n\n\tif _, err := io.Copy(tmpFile, reader); err != nil {\n\t\t_ = tmpFile.Close()\n\t\treturn fmt.Errorf(\"copy L0 file: %w\", err)\n\t}\n\n\tif err := tmpFile.Sync(); err != nil {\n\t\t_ = tmpFile.Close()\n\t\treturn fmt.Errorf(\"sync L0 file: %w\", err)\n\t}\n\n\tif err := tmpFile.Close(); err != nil {\n\t\treturn fmt.Errorf(\"close L0 file: %w\", err)\n\t}\n\n\t// Atomically rename temp file to final path\n\tif err := os.Rename(tmpPath, localPath); err != nil {\n\t\treturn fmt.Errorf(\"rename L0 file: %w\", err)\n\t}\n\tdb.invalidatePosCache()\n\n\tdb.Logger.Info(\"fetched latest L0 file from replica\",\n\t\t\"min_txid\", minTXID,\n\t\t\"max_txid\", maxTXID)\n\n\treturn nil\n}\n\n// verify ensures the current LTX state matches where it left off from\n// the real WAL. Check info.ok if verification was successful.\nfunc (db *DB) verify(ctx context.Context, state *syncState) (info syncInfo, err error) {","sourceCodeStart":1634,"sourceCodeEnd":1670,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/db.go#L1634-L1670","documentation":"After fsync, Litestream closes the temp file with tmpFile.Close(). This error wraps a failure of that close, indicating pending buffered data could not be flushed by the OS or the file descriptor is in a bad state. The partially staged file is discarded and the LTX file is not adopted.","triggerScenarios":"checkDatabaseBehindReplica calls tmpFile.Close() after a successful Sync and close fails — rare, usually EIO on flush of remaining buffers, or fd exhaustion earlier in the process causing odd fd states.","commonSituations":"Underlying storage device errors (dmesg shows I/O errors); file descriptor limit (ulimit -n) exhausted after many open LTX files; NFS server issues delaying writeback.","solutions":["Check dmesg/journal for block-device I/O errors on the data volume.","Raise the process file-descriptor limit (ulimit -n / LimitNOFILE in systemd) if fd exhaustion is reported.","Fix or replace failing storage; close errors on local disks almost always indicate hardware/driver problems.","Retry after remediation — the temp file is cleaned up and the next sync refetches."],"exampleFix":"# before: systemd service hits fd limit\n# after: raise LimitNOFILE for litestream\n[Service]\nLimitNOFILE=65536","handlingStrategy":"try-catch","validationCode":"// Ensure adequate fd headroom\nvar lim syscall.Rlimit\nsyscall.Getrlimit(syscall.RLIMIT_NOFILE, &lim)\nif lim.Cur < 4096 { log.Printf(\"low RLIMIT_NOFILE: %d\", lim.Cur) }","typeGuard":"null","tryCatchPattern":"if err := tmpFile.Close(); err != nil {\n    return fmt.Errorf(\"close L0 file: %w\", err)\n} // close errors are almost always EIO: check hardware/driver logs, then retry","preventionTips":["Set LimitNOFILE=65536 for the litestream systemd unit","Monitor storage hardware health","Check journal/dmesg when close errors appear","Avoid NFS for the LTX directory where writeback is unreliable"],"tags":["litestream","filesystem","file-handle","io","l0"],"backgroundTag":"file-write-failed","analyzedSha":"4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3","analyzedAt":"2026-09-06T18:29:25.564Z","contentChangedAt":"2026-09-06T18:29:25.564Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}