hashicorp/terraform · error

Failed to upload script

Error message

Failed to upload script: %v

What it means

The remote-exec provisioner's runScripts function wraps UploadScript failures with this message. After establishing a connection, it calls comm.UploadScript to copy each script to the remote machine at comm.ScriptPath(). Any error during the upload (SSH/WinRM transfer failure, disk full, permission denied on the remote temp directory) is wrapped and returned.

Solutions

  1. Ensure the remote machine has a writable temp directory (typically /tmp on Linux).
  2. Verify the connection user has write access to the default script path on the remote.
  3. Check disk space on the remote with a pre-flight SSH check.
  4. Stabilize the connection by increasing timeout or using a bastion host.

Example fix

# before
connection {
  type    = "ssh"
  host    = var.ip
  user    = "ubuntu"
}
provisioner "remote-exec" {
  inline = ["echo hello"]
}

# after — add timeout and verify remote /tmp
connection {
  type    = "ssh"
  host    = var.ip
  user    = "ubuntu"
  timeout = "5m"
}
provisioner "remote-exec" {
  inline = [
    "test -w /tmp || { echo '/tmp not writable'; exit 1; }",
    "echo hello"
  ]
}
Defensive patterns

Strategy: retry

Validate before calling

// Before runScripts, verify remote connectivity and temp dir
// (best done via a quick remote-exec inline check)
// Check connection is alive
if err := comm.Connect(nil); err != nil {
    return fmt.Errorf("connection failed before upload: %w", err)
}

Try / catch

// Retry script upload
for i := 0; i < 3; i++ {
    err := comm.UploadScript(remotePath, script)
    if err == nil {
        break
    }
    if i == 2 {
        return fmt.Errorf("Failed to upload script after retries: %v", err)
    }
    comm.Disconnect()
    time.Sleep(time.Duration(1<<i) * time.Second)
    comm.Connect(nil)
}

Prevention

When it happens

Trigger: Running a remote-exec provisioner where comm.UploadScript (resource_provisioner.go:269) fails. This happens after a successful connection but during the file transfer of the script to the remote machine. The remote temp directory may not exist, be unwritable, or the connection may drop mid-transfer.

Common situations: The remote machine's temporary directory (where ScriptPath points) does not exist or is not writable. The SSH connection is established but drops during transfer. Insufficient disk space on the remote for the script content. SELinux or AppArmor blocking writes to the default script path.

Related errors


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

Appendix: source

Thrown at internal/builtin/provisioners/remote-exec/resource_provisioner.go:270

		<-cmdCtx.Done()
		comm.Disconnect()
	}()

	for _, script := range scripts {
		var cmd *remote.Cmd

		outR, outW := io.Pipe()
		errR, errW := io.Pipe()
		defer outW.Close()
		defer errW.Close()

		go copyUIOutput(o, outR)
		go copyUIOutput(o, errR)

		remotePath := comm.ScriptPath()

		if err := comm.UploadScript(remotePath, script); err != nil {
			return fmt.Errorf("Failed to upload script: %v", err)
		}

		cmd = &remote.Cmd{
			Command: remotePath,
			Stdout:  outW,
			Stderr:  errW,
		}
		if err := comm.Start(cmd); err != nil {
			return fmt.Errorf("Error starting script: %v", err)
		}

		if err := cmd.Wait(); err != nil {
			return err
		}

		// Upload a blank follow up file in the same path to prevent residual
		// script contents from remaining on remote machine
		empty := bytes.NewReader([]byte(""))

View on GitHub (pinned to d32a084675)