hashicorp/terraform · error
Upload failed
Error message
Upload failed: %v
What it means
The file provisioner's copyFiles function wraps UploadDir failures with 'Upload failed: %v'. When the source path is a directory (info.IsDir() is true at resource_provisioner.go:186), the provisioner calls comm.UploadDir to recursively transfer it to the remote machine. Any error from the communicator (SSH, WinRM) during directory upload propagates with this wrapper.
Solutions
- Verify the remote destination path is writable by the SSH/WinRM user specified in the connection block.
- Check that the source directory exists and is readable locally with `ls -la <source>`.
- Increase the connection timeout or add a bastion host if the SSH connection is unstable.
- Reduce the directory size or split into smaller transfers if the connection is dropping due to transfer volume.
Example fix
# before
connection {
type = "ssh"
host = var.ip
user = "ubuntu"
timeout = "30s"
}
provisioner "file" {
source = "./config-dir"
destination = "/etc/myapp"
}
# after — increase timeout and ensure remote dir exists
connection {
type = "ssh"
host = var.ip
user = "ubuntu"
timeout = "5m"
}
provisioner "remote-exec" {
inline = ["sudo mkdir -p /etc/myapp && sudo chown ubuntu:ubuntu /etc/myapp"]
}
provisioner "file" {
source = "./config-dir"
destination = "/etc/myapp"
} Defensive patterns
Strategy: retry
Validate before calling
// Before provisioning, verify the source directory exists and is readable
info, err := os.Stat(src)
if err != nil {
return fmt.Errorf("source directory not accessible: %w", err)
}
if !info.IsDir() {
return fmt.Errorf("source is not a directory: %s", src)
}
// Check destination path will be writable (best-effort)
// via a pre-flight remote-exec check Try / catch
// Retry directory upload with exponential backoff
maxRetries := 3
for i := 0; i < maxRetries; i++ {
err := comm.UploadDir(dst, src)
if err == nil {
break
}
if i == maxRetries-1 {
return fmt.Errorf("Upload failed after %d attempts: %v", maxRetries, err)
}
time.Sleep(time.Duration(1<<i) * time.Second)
} Prevention
- Ensure the remote destination directory exists and is writable before the file provisioner runs.
- Use a remote-exec provisioner with inline commands to create the destination directory first.
- Set a generous connection timeout in the connection block for large directory transfers.
- Verify SSH key permissions and network stability before applying.
When it happens
Trigger: Running a file provisioner whose 'source' points to a directory, when the communicator's UploadDir method fails. Common causes: SSH/WinRM connection drops mid-transfer, permission denied on the remote destination, insufficient disk space on remote, or the communicator returns an internal I/O error.
Common situations: Uploading a directory of configuration files or scripts to a remote instance via the file provisioner during 'terraform apply'. The remote machine has restrictive permissions on the destination path. The SSH connection is unstable or times out during a large directory transfer.
Related errors
- Failed to upload script
- connection type ' ' not supported
- Error chmodding script file to 0777 in remote machine
- Error connecting to bastion
- Error connecting to proxy
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/c2aa550abe28b2a4.
Report an issue: GitHub.
Appendix: source
Thrown at internal/builtin/provisioners/file/resource_provisioner.go:188
return err
}
// disconnect when the context is canceled, which will close this after
// Apply as well.
go func() {
<-ctx.Done()
comm.Disconnect()
}()
info, err := os.Stat(src)
if err != nil {
return err
}
// If we're uploading a directory, short circuit and do that
if info.IsDir() {
if err := comm.UploadDir(dst, src); err != nil {
return fmt.Errorf("Upload failed: %v", err)
}
return nil
}
// We're uploading a file...
f, err := os.Open(src)
if err != nil {
return err
}
defer f.Close()
err = comm.Upload(dst, f)
if err != nil {
return fmt.Errorf("Upload failed: %v", err)
}
return err
}View on GitHub (pinned to d32a084675)