hashicorp/terraform · error

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

Error message

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

What it means

Thrown when replacefile.AtomicRename fails to atomically move the freshly-written temp file over the real credentials file. AtomicRename performs an OS-level rename (rename(2) on Unix, MoveFileEx with MOVEFILE_REPLACE_EXISTING on Windows); failure means the rename syscall itself failed, not the write.

Source

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

			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: %s", 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: %s", 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: %s", filename, err)
		}

		moved = true
	}

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

View on GitHub (pinned to d32a084675)

Solutions

  1. Close any editor or other Terraform process holding the credentials file open, then retry.
  2. Ensure the parent directory of the credentials file is writable and on the same filesystem as the temp file (no cross-mount symlink).
  3. Check SELinux/AppArmor audit logs for denials (`ausearch -m avc` / `dmesg | grep -i denied`).
  4. On persistent EXDEV, remove symlinks in the credentials path so temp and target share one filesystem.
Defensive patterns

Strategy: try-catch

Try / catch

// Same-filesystem check to pre-empt EXDEV-style rename failures
func sameFS(a, b string) bool {
    var sa, sb syscall.Stat_t
    if syscall.Stat(a, &sa) != nil { return false }
    if syscall.Stat(b, &sb) != nil { return false }
    return sa.Dev == sb.Dev
}

Prevention

When it happens

Trigger: Source and destination are on different filesystems (EXDEV on POSIX — should not happen since temp is created in the same dir, but can if the dir spans a bind mount); destination is a directory or the parent lacks write permission; on Windows the destination is open in another process; SELinux/AppArmor denies the rename.

Common situations: Another Terraform process or editor holds the file open (Windows); a security module blocks cross-context rename; the credentials path was redirected across a mount boundary by a symlink; the parent directory is not writable.

Related errors


AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11). Data as JSON: /api/errors/d9e7fd10ee9c4f78. Report an issue: GitHub.