opentofu/opentofu · error
Upload failed: %w
Error message
Upload failed: %w
What it means
The file provisioner wraps communicator errors from uploading a directory (comm.UploadDir) in 'Upload failed: %w'. The underlying cause is typically lost connectivity, permission denial on the remote destination, an invalid destination path, or a full disk on the target.
Source
Thrown at internal/builtin/provisioners/file/resource_provisioner.go:215
// disconnect when the context is canceled, which will close this after
// Apply as well.
go func() {
<-ctx.Done()
if err := comm.Disconnect(); err != nil {
log.Printf("[ERROR] Unable to close provisioner connection: %s", err.Error())
}
}()
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: %w", 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: %w", err)
}
return err
}View on GitHub (pinned to 3561785c48)
Solutions
- Verify connectivity from the same host (manual ssh/winrm to the target) and check the connection block settings.
- Make destination an absolute path that exists and is writable by the login user.
- Check disk space and directory permissions on the target.
- For slow or flaky links, raise connection timeout or upload a single archive and unpack it with remote-exec instead of a directory tree.
Example fix
# before
event = "relative/dir" # destination = "relative/dir" (ambiguous/unsupported)
provisioner "file" { source = "conf/", destination = "conf" }
# after: absolute destination path
provisioner "file" { source = "conf/", destination = "/etc/myapp/conf" } Defensive patterns
Strategy: retry
Validate before calling
# CI pre-flight from the same host that runs apply ssh -o BatchMode=yes user@target 'test -w /etc/myapp/conf || echo NOT_WRITABLE'
Try / catch
if err := comm.UploadDir(dst, src); err != nil {
// transient transport failures (EOF, timeout) are retryable;
// permission errors are not — inspect the wrapped error
if isTransient(err) { time.Sleep(backoff); retry() }
} Prevention
- Use absolute destination paths that exist and are writable by the connection user.
- Set realistic connection timeouts for large trees.
- Upload one archive and unpack with remote-exec instead of many small files.
- Test connectivity from the same host/bastion before apply.
When it happens
Trigger: provisioner "file" with source pointing at a directory during apply, where the SSH/WinRM transfer of the directory tree fails mid-operation.
Common situations: Destination path not absolute or not writable by the login user; connection dropped through a bastion/NAT timeout; disk full on the target; WinRM path-style mismatches; uploading many small files over a slow link until timeout.
Related errors
- Failed to upload script: %w
- Error starting script: %w
- 'winrm' connections are not supported in OpenTofu v1.13 or l
- missing provisioner schema
- Failed to upload state to %v: %w
AI-assisted analysis of opentofu/opentofu@3561785c48 (2026-08-15).
Data as JSON: /api/errors/28d8c89268661bef.
Report an issue: GitHub.