{"record":{"id":"a77144734eef0925","repo":"benbjohnson/litestream","slug":"rename-txid-file-w","errorCode":null,"errorMessage":"rename txid file: %w","messagePattern":"rename txid file: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"replica.go","lineNumber":1744,"sourceCode":"\t\treturn fmt.Errorf(\"create txid temp file: %w\", err)\n\t}\n\tdefer f.Close()\n\tdefer os.Remove(tmpPath)\n\n\tif _, err := fmt.Fprintln(f, txid); err != nil {\n\t\treturn fmt.Errorf(\"write txid: %w\", err)\n\t}\n\n\tif err := f.Sync(); err != nil {\n\t\treturn fmt.Errorf(\"sync txid file: %w\", err)\n\t}\n\n\tif err := f.Close(); err != nil {\n\t\treturn fmt.Errorf(\"close txid file: %w\", err)\n\t}\n\n\tif err := os.Rename(tmpPath, txidPath); err != nil {\n\t\treturn fmt.Errorf(\"rename txid file: %w\", err)\n\t}\n\n\tif err := internal.FsyncDir(filepath.Dir(txidPath)); err != nil {\n\t\treturn fmt.Errorf(\"sync txid dir: %w\", err)\n\t}\n\treturn nil\n}\n\n// ReadTXIDFile reads the TXID from a sidecar file at <outputPath>-txid.\n// Returns 0, nil if the file does not exist (first run).\nfunc ReadTXIDFile(outputPath string) (ltx.TXID, error) {\n\ttxidPath := TXIDPath(outputPath)\n\n\tdata, err := os.ReadFile(txidPath)\n\tif os.IsNotExist(err) {\n\t\treturn 0, nil\n\t} else if err != nil {\n\t\treturn 0, fmt.Errorf(\"read txid file: %w\", err)","sourceCodeStart":1726,"sourceCodeEnd":1762,"githubUrl":"https://github.com/benbjohnson/litestream/blob/4ed7a308f6271ebfd2b0a6e4b70b03011a37e4a3/replica.go#L1726-L1762","documentation":"After writing and fsyncing the temp file, WriteTXIDFile atomically renames '<outputPath>-txid.tmp' to '<outputPath>-txid'. This error means os.Rename failed, so the new TXID was never published; the previous TXID file (if any) remains untouched. Rename failures typically indicate a path-level problem rather than data corruption.","triggerScenarios":"os.Rename(tmpPath, txidPath) failing because the target directory was removed mid-operation, the output path crosses filesystem boundaries (rename EXDEV), permission denied on the directory, or the target path is invalid/too long.","commonSituations":"Output directory deleted or recreated while litestream is running; output path pointing into a mounted volume where temp file and target end up on different devices; read-only or permission-restricted restore directories; restore path with a very long name.","solutions":["Verify the directory of the output path exists and is writable by the litestream process","Ensure the temp file and target are on the same filesystem (rename cannot cross devices) — keep outputPath on one volume","Check permissions and path length for the '<outputPath>-txid' location","Re-run restore/replication; the temp file is cleaned up by defer so a retry starts clean"],"exampleFix":"// before: writing temp file in a different filesystem than target\ntmpPath := \"/tmp/mydb-txid.tmp\" // then rename to /var/lib/db/mydb-txid\n// after\ntmpPath := finalPath + \".tmp\" // same directory, same filesystem","handlingStrategy":"validation","validationCode":"dir := filepath.Dir(TXIDPath(outputPath))\nif st, err := os.Stat(dir); err != nil || !st.IsDir() {\n    return fmt.Errorf(\"output dir missing: %s\", dir)\n}","typeGuard":"func renameable(tmp, dst string) bool {\n    return filepath.Dir(tmp) == filepath.Dir(dst) // same fs required\n}","tryCatchPattern":"if err := WriteTXIDFile(outputPath, txid); err != nil {\n    if errors.Is(err, syscall.EXDEV) || errors.Is(err, syscall.ENOENT) {\n        // recreate dir / keep temp file next to target, then retry\n    }\n    return err\n}","preventionTips":["Always create the temp file in the same directory as the target","Do not delete or recreate the database output directory while litestream runs","Keep paths under filesystem path-length limits","Grant write permission on the output directory to the litestream user"],"tags":["filesystem","rename","atomic-write","litestream"],"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-14T05:17:10.506Z"}