{"record":{"id":"c7853f5ffb441e5c","repo":"wavetermdev/waveterm","slug":"failed-to-rename-temp-file-q-to-q-w-also-fail","errorCode":null,"errorMessage":"failed to rename temp file %q to %q: %w (also failed to remove temp file: %v)","messagePattern":"failed to rename temp file %q to %q: %w \\(also failed to remove temp file: (.+?)\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/util/fileutil/fileutil.go","lineNumber":189,"sourceCode":"\t}\n\text := strings.ToLower(filepath.Ext(path))\n\tif mimeType, ok := StaticMimeTypeMap[ext]; ok {\n\t\treturn mimeType\n\t}\n\treturn \"\"\n}\n\nfunc AtomicWriteFile(fileName string, data []byte, perm os.FileMode) error {\n\ttmpFileName := fileName + TempFileSuffix\n\tif err := os.WriteFile(tmpFileName, data, perm); err != nil {\n\t\tif removeErr := os.Remove(tmpFileName); removeErr != nil && !os.IsNotExist(removeErr) {\n\t\t\treturn fmt.Errorf(\"failed to write temp file %q: %w (also failed to remove temp file: %v)\", tmpFileName, err, removeErr)\n\t\t}\n\t\treturn err\n\t}\n\tif err := os.Rename(tmpFileName, fileName); err != nil {\n\t\tif removeErr := os.Remove(tmpFileName); removeErr != nil && !os.IsNotExist(removeErr) {\n\t\t\treturn fmt.Errorf(\"failed to rename temp file %q to %q: %w (also failed to remove temp file: %v)\", tmpFileName, fileName, err, removeErr)\n\t\t}\n\t\treturn err\n\t}\n\treturn nil\n}\n\nvar (\n\tsystemBinDirs = []string{\n\t\t\"/bin/\",\n\t\t\"/usr/bin/\",\n\t\t\"/usr/local/bin/\",\n\t\t\"/opt/bin/\",\n\t\t\"/sbin/\",\n\t\t\"/usr/sbin/\",\n\t}\n\tsuspiciousPattern = regexp.MustCompile(`[:;#!&$\\t%=\"|>{}]`)\n\tflagPattern       = regexp.MustCompile(` --?[a-zA-Z0-9]`)\n)","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/wavetermdev/waveterm/blob/a4447c1563b2df285ab89e76c82f91e1a1a49c1e/pkg/util/fileutil/fileutil.go#L171-L207","documentation":"AtomicWriteFile writes to a temp file and then renames it onto the target. This error is returned when os.Rename fails and the subsequent attempt to remove the temp file also fails, wrapping both errors. The original target file is left untouched; a stale .tmp file may remain.","triggerScenarios":"os.Rename(tmpFileName, fileName) failing (target path is a directory, cross-device rename, target locked/permission issue) combined with os.Remove(tmpFileName) failing for a reason other than NotExist.","commonSituations":"Target path exists as a directory; /tmp-style cross-filesystem setups when temp and target are on different mounts; an open file handle or AV scanner holding the temp file on Windows; permission mismatch between temp and target directories.","solutions":["Ensure the target path is not a directory and its parent has write permission.","Ensure the temp file and target are on the same filesystem (write temp next to the target, which this function already does — so check for mount-point changes).","Manually remove the stale fileName+\".tmp\" file, then retry.","Check for processes locking the target (editors, sync clients, antivirus) and retry."],"exampleFix":"// before\nfileutil.AtomicWriteFile(\"/home/user/.config/wave\", data, 0644) // ~/.config/wave is a directory\n\n// after\nif fi, err := os.Stat(target); err == nil && fi.IsDir() {\n    return fmt.Errorf(\"target %s is a directory\", target)\n}\nreturn fileutil.AtomicWriteFile(target, data, 0644)","handlingStrategy":"retry","validationCode":"// ensure target is not a directory and temp file is absent\nif fi, err := os.Stat(fileName); err == nil && fi.IsDir() {\n    return fmt.Errorf(\"target %s is a directory\", fileName)\n}\nos.Remove(fileName + \".tmp\") // ignore NotExist","typeGuard":null,"tryCatchPattern":"// Go: retry rename failures after cleanup\nif err := fileutil.AtomicWriteFile(f, data, 0644); err != nil {\n    if strings.Contains(err.Error(), \"failed to rename temp file\") {\n        os.Remove(f + \".tmp\")\n        time.Sleep(50 * time.Millisecond)\n        err = fileutil.AtomicWriteFile(f, data, 0644) // retry once\n    }\n}","preventionTips":["Confirm the target path is a file, not a directory","Keep temp and target on the same filesystem","Avoid concurrent writers to the same target path","Account for AV/sync tools that briefly lock files on Windows"],"tags":["go","filesystem","atomic-write","rename"],"backgroundTag":"atomic-rename-failed","analyzedSha":"a4447c1563b2df285ab89e76c82f91e1a1a49c1e","analyzedAt":"2026-09-01T15:26:23.972Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}