hashicorp/terraform · error
SCP failed to start. This usually means that SCP is…
Error message
SCP failed to start. This usually means that SCP is not properly installed on the remote system.
What it means
Returned by the SCP upload/download path when the remote `scp` command exits with status 127 (command not found). The communicator maps 127 specifically to this human-readable error explaining SCP is missing or not on PATH on the remote host.
Solutions
- Install an SCP provider on the remote: `apt-get install openssh-client` / `yum install openssh-clients` / the alpine `openssh-client` package.
- Ensure the SSH user's non-interactive PATH includes the directory containing `scp` (set it in `.bashrc`/`.ssh/environment` with `PermitUserEnvironment`).
- If SCP cannot be installed, switch the connection `type` to `winrm` (Windows) or avoid file uploads for this host.
Example fix
# before: connection { type = "ssh" } to a host without scp -> error on file upload
# after: install openssh-client on the remote, e.g.
# sudo apt-get update && sudo apt-get install -y openssh-client Defensive patterns
Strategy: validation
Validate before calling
// Probe for scp before relying on file uploads (run over an existing session): // ssh <host> "command -v scp >/dev/null 2>&1 && echo ok || echo missing" // If 'missing', install openssh-client on the remote first.
Try / catch
if err := comm.Upload(dst, src); err != nil {
if strings.Contains(err.Error(), "SCP failed to start") {
return fmt.Errorf("scp missing on remote host %q: install openssh-client", host)
}
return err
} Prevention
- Bake openssh-client into base images used as Terraform provisioner targets.
- Ensure the SSH user's non-interactive PATH includes /usr/bin.
- Prefer the `file`/`remote-exec` provisioners only on hosts you control and can provision SCP on.
When it happens
Trigger: `scp -rvd <dst>` (or the download variant) is run over the SSH session and the remote shell returns exit 127 — `scp` binary is absent or not in PATH for the SSH user's non-interactive shell.
Common situations: Minimal/container remote images without openssh-clients; a non-login SSH shell whose PATH differs from the interactive one and omits `/usr/bin/scp`; stripped-down appliances.
Related errors
- Cannot quote scp command, target platform unknown
- Error creating temporary file for upload
- Error reading error message
- ssh client is not connected
- Connection Error: StatusCode
AI-assisted analysis of hashicorp/terraform@d32a084675 (2026-08-11).
Data as JSON: /api/errors/2815bc910fc208b8.
Report an issue: GitHub.
Appendix: source
Thrown at internal/communicator/ssh/communicator.go:613
log.Println("[DEBUG] Waiting for SSH session to complete.")
err = session.Wait()
// log any stderr before exiting on an error
scpErr := stderr.String()
if len(scpErr) > 0 {
log.Printf("[ERROR] scp stderr: %q", stderr)
}
if err != nil {
if exitErr, ok := err.(*ssh.ExitError); ok {
// Otherwise, we have an ExitErorr, meaning we can just read
// the exit status
log.Printf("[ERROR] %s", exitErr)
// If we exited with status 127, it means SCP isn't available.
// Return a more descriptive error for that.
if exitErr.ExitStatus() == 127 {
return errors.New(
"SCP failed to start. This usually means that SCP is not\n" +
"properly installed on the remote system.")
}
}
return err
}
return nil
}
// checkSCPStatus checks that a prior command sent to SCP completed
// successfully. If it did not complete successfully, an error will
// be returned.
func checkSCPStatus(r *bufio.Reader) error {
code, err := r.ReadByte()
if err != nil {
return errView on GitHub (pinned to d32a084675)