{"record":{"id":"f1692687833be1d4","repo":"opentofu/opentofu","slug":"failed-to-replace-s-with-temporary-file-s-w","errorCode":null,"errorMessage":"failed to replace %s with temporary file %s: %w","messagePattern":"failed to replace (.+?) with temporary file (.+?): %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/command/cliconfig/credentials.go","lineNumber":429,"sourceCode":"\t\t\tif !moved {\n\t\t\t\tos.Remove(name)\n\t\t\t}\n\t\t}(f, tmpName)\n\n\t\t// Write the credentials to the temporary file, then immediately close\n\t\t// it, whether or not the write succeeds.\n\t\t_, err = f.Write(newSrc)\n\t\tf.Close()\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"cannot write to temporary file %s: %w\", tmpName, err)\n\t\t}\n\n\t\t// Temporary file now replaces the original file, as atomically as\n\t\t// possible. (At the very least, we should not end up with a file\n\t\t// containing only a partial JSON object.)\n\t\terr = replacefile.AtomicRename(tmpName, filename)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"failed to replace %s with temporary file %s: %w\", filename, tmpName, err)\n\t\t}\n\n\t\t// Credentials file should be readable only by its owner. (This may\n\t\t// not be effective on all platforms, but should at least work on\n\t\t// Unix-like targets and should be harmless elsewhere.)\n\t\tif err := os.Chmod(filename, 0600); err != nil {\n\t\t\treturn fmt.Errorf(\"cannot set mode for credentials file %s: %w\", filename, err)\n\t\t}\n\n\t\tmoved = true\n\t}\n\n\tif new != nil {\n\t\ts.configured[host] = new.ToStore()\n\t} else {\n\t\tdelete(s.configured, host)\n\t}\n","sourceCodeStart":411,"sourceCodeEnd":447,"githubUrl":"https://github.com/opentofu/opentofu/blob/3561785c48c1ce615e7c50261bd351f26053efa2/internal/command/cliconfig/credentials.go#L411-L447","documentation":"The final atomicity step renames the temp file over credentials.tfrc.json via replacefile.AtomicRename. Failure means the platform refused the rename: on Windows, the target is open by another process (editor, antivirus, sync agent); on POSIX, cross-device rename, missing target permissions, or filesystem errors. The temp file is cleaned up by the deferred remove and the original file is unchanged.","triggerScenarios":"An editor or file-sync tool (OneDrive/Dropbox) holding credentials.tfrc.json open on Windows; antivirus scanning the freshly renamed file; the config dir and temp file ending up on different mounts; NFS rename semantics failing.","commonSituations":"tofu login while the credentials file is open in VS Code; sync clients watching the home dir; heavily AV-instrumented corporate Windows machines.","solutions":["Close editors/sync tools that may hold the credentials file open, then retry tofu login","On Windows, exclude the tofu config dir from on-access AV scanning, or retry after a short delay (scans are transient)","Ensure the config dir and its temp files live on the same filesystem/mount"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"err := src.StoreForHost(ctx, host, creds)\nif err != nil && strings.Contains(err.Error(), \"failed to replace\") {\n\t// Windows: target usually held open by AV/editor; close and retry\n\tfor attempt := 0; attempt < 3; attempt++ {\n\t\ttime.Sleep(500 * time.Millisecond)\n\t\tif err = src.StoreForHost(ctx, host, creds); err == nil {\n\t\t\tbreak\n\t\t}\n\t}\n}","preventionTips":["Close editors and pause sync clients (OneDrive/Dropbox) before tofu login/logout on Windows","Exclude the tofu config dir from on-access antivirus scans on managed endpoints","Keep the config dir off NFS where rename semantics are unreliable"],"tags":["filesystem","credentials","rename","windows","atomicity"],"backgroundTag":null,"analyzedSha":"3561785c48c1ce615e7c50261bd351f26053efa2","analyzedAt":"2026-08-15T23:27:16.226Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}