{"record":{"id":"6bfd05a182f2778f","repo":"benbjohnson/litestream","slug":"rename-l0-file-w","errorCode":null,"errorMessage":"rename L0 file: %w","messagePattern":"rename L0 file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"db.go","lineNumber":1657,"sourceCode":"\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) {\n\tpos, err := db.Pos()\n\tif err != nil {\n\t\treturn info, fmt.Errorf(\"pos: %w\", err)\n\t}\n","sourceCodeStart":1639,"sourceCodeEnd":1675,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/db.go#L1639-L1675","documentation":"The final step stages the fetched LTX file by atomically renaming tmpPath to the final LTX path within the L0 directory. This error wraps os.Rename failing, meaning the fetched file could not be adopted even though it downloaded successfully.","triggerScenarios":"checkDatabaseBehindReplica calls os.Rename(tmpPath, localPath) after a successful Close and the rename fails — the target path exists in a way rename can't replace (directory), the L0 dir permissions changed, the source .tmp was removed by an external cleaner, or the filesystem doesn't support atomic rename across the involved paths.","commonSituations":"A cleanup job (tmpwatch/cron) deleted the .tmp between close and rename; target path turned into a directory due to a prior corrupt state; different filesystems for temp and target paths after a bind-mount change; Windows/limited network filesystems with weak rename semantics.","solutions":["Ensure nothing else (cron jobs, antivirus, other litestream instances) touches the LTX directory while litestream runs.","Check that localPath is not an existing directory (ls -ld) and remove bad state, or run `litestream reset` to rebuild local LTX state.","Verify tmp and final paths are on the same filesystem (they should be — both derive from LTXPath in the same dir); fix bind-mount changes.","Inspect the wrapped OS error for the exact path and errno, then let the next sync retry."],"exampleFix":"// before: cron cleaner removes *.tmp mid-fetch\n*/5 * * * * find /var/lib/db -name '*.tmp' -delete\n// after: exclude the litestream LTX dir from cleanup\n*/5 * * * * find /var/lib/db -name '*.tmp' -not -path '*/ltx/*' -delete","handlingStrategy":"validation","validationCode":"// Ensure no competing cleaner or stale target before fetch\nif fi, err := os.Lstat(localPath); err == nil && fi.IsDir() {\n    log.Fatalf(\"target path is a directory: %s\", localPath)\n}","typeGuard":"null","tryCatchPattern":"if err := os.Rename(tmpPath, localPath); err != nil {\n    return fmt.Errorf(\"rename L0 file: %w\", err)\n} // if persistent, `litestream reset` rebuilds local LTX state cleanly","preventionTips":["Exclude ltx/ trees from cron cleaners, antivirus, and sync tools","Run a single litestream instance per database","Keep temp and final paths on the same filesystem (default behavior)","Use `litestream reset` for corrupt local state instead of manual surgery"],"tags":["litestream","filesystem","rename","atomic","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"}