opentofu/opentofu · error

failed to replace %s with temporary file %s: %w

Error message

failed to replace %s with temporary file %s: %w

What it means

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.

Source

Thrown at internal/command/cliconfig/credentials.go:429

			if !moved {
				os.Remove(name)
			}
		}(f, tmpName)

		// Write the credentials to the temporary file, then immediately close
		// it, whether or not the write succeeds.
		_, err = f.Write(newSrc)
		f.Close()
		if err != nil {
			return fmt.Errorf("cannot write to temporary file %s: %w", tmpName, err)
		}

		// Temporary file now replaces the original file, as atomically as
		// possible. (At the very least, we should not end up with a file
		// containing only a partial JSON object.)
		err = replacefile.AtomicRename(tmpName, filename)
		if err != nil {
			return fmt.Errorf("failed to replace %s with temporary file %s: %w", filename, tmpName, err)
		}

		// Credentials file should be readable only by its owner. (This may
		// not be effective on all platforms, but should at least work on
		// Unix-like targets and should be harmless elsewhere.)
		if err := os.Chmod(filename, 0600); err != nil {
			return fmt.Errorf("cannot set mode for credentials file %s: %w", filename, err)
		}

		moved = true
	}

	if new != nil {
		s.configured[host] = new.ToStore()
	} else {
		delete(s.configured, host)
	}

View on GitHub (pinned to 3561785c48)

Solutions

  1. Close editors/sync tools that may hold the credentials file open, then retry tofu login
  2. On Windows, exclude the tofu config dir from on-access AV scanning, or retry after a short delay (scans are transient)
  3. Ensure the config dir and its temp files live on the same filesystem/mount
Defensive patterns

Strategy: retry

Try / catch

err := src.StoreForHost(ctx, host, creds)
if err != nil && strings.Contains(err.Error(), "failed to replace") {
	// Windows: target usually held open by AV/editor; close and retry
	for attempt := 0; attempt < 3; attempt++ {
		time.Sleep(500 * time.Millisecond)
		if err = src.StoreForHost(ctx, host, creds); err == nil {
			break
		}
	}
}

Prevention

When it happens

Trigger: 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.

Common situations: tofu login while the credentials file is open in VS Code; sync clients watching the home dir; heavily AV-instrumented corporate Windows machines.

Related errors


AI-assisted analysis of opentofu/opentofu@3561785c48 (2026-08-15). Data as JSON: /api/errors/f1692687833be1d4. Report an issue: GitHub.