hashicorp/terraform · error

ssh client is not connected

Error message

ssh client is not connected

What it means

Returned by Communicator.newSession (communicator.go:522). When a SCP/SSH command is requested but c.client (the *ssh.Client) is nil — the connection was never established or was torn down — newSession returns this error. Notably it then immediately attempts c.Connect(nil) to reconnect and retries c.client.NewSession(); the caller only sees this message if that reconnect also fails to set up a session.

Source

Thrown at internal/communicator/ssh/communicator.go:522

		if src[len(src)-1] != '/' {
			log.Printf("[DEBUG] No trailing slash, creating the source directory name")
			return scpUploadDirProtocol(filepath.Base(src), w, r, uploadEntries)
		}
		// Trailing slash, so only upload the contents
		return uploadEntries()
	}

	cmd, err := quoteScpCommand([]string{"scp", "-rvt", dst}, c.connInfo.TargetPlatform)
	if err != nil {
		return err
	}
	return c.scpSession(cmd, scpFunc)
}

func (c *Communicator) newSession() (session *ssh.Session, err error) {
	log.Println("[DEBUG] opening new ssh session")
	if c.client == nil {
		err = errors.New("ssh client is not connected")
	} else {
		session, err = c.client.NewSession()
	}

	if err != nil {
		log.Printf("[WARN] ssh session open error: '%s', attempting reconnect", err)
		if err := c.Connect(nil); err != nil {
			return nil, err
		}

		return c.client.NewSession()
	}

	return session, nil
}

func (c *Communicator) scpSession(scpCommand string, f func(io.Writer, *bufio.Reader) error) error {
	session, err := c.newSession()

View on GitHub (pinned to c9def3e214)

Solutions

  1. Verify connectivity: ensure the host/port are reachable and credentials (connection block: host, port, private_key/password) are correct.
  2. For bastion/relay setups, confirm the bastion is reachable and the ProxyJump/bastion_host config is valid.
  3. Increase retries or add a depends_on so the resource network is up before the provisioner runs; check that Connect() succeeds by testing `ssh <host>` manually.

Example fix

# before
 resource "null_resource" "x" {
   provisioner "file" {  # client nil if host not ready
     connection { type = "ssh" host = aws_instance.w.public_ip }
   }
 }
# after: ensure instance/network are ready first
 resource "null_resource" "x" {
   depends_on = [aws_internet_gateway.main, aws_instance.w]
   provisioner "file" {
     connection {
       type        = "ssh"
       host        = aws_instance.w.public_ip
       private_key = file("~/.ssh/id_rsa")
     }
   }
 }
Defensive patterns

Strategy: retry

Validate before calling

// Validate connection config and reachability before the provisioner runs.
 if conn.Host == "" || !reachable(conn.Host, conn.Port) {
     return errors.New("ssh target not reachable; fix connection block / network")
 }

Try / catch

// newSession already reconnects on failure; wrap caller logic to retry once.
 err := communicator.Upload(dst, src)
 if err != nil && strings.Contains(err.Error(), "not connected") {
     if cerr := communicator.Connect(nil); cerr == nil {
         err = communicator.Upload(dst, src)
     }
 }

Prevention

When it happens

Trigger: A provisioner (connection { type="ssh" }) tries to upload a file / run a command before Connect() succeeded, or after the underlying SSH connection dropped and the auto-reconnect in newSession could not re-establish it.

Common situations: Remote host unreachable / wrong port; SSH key auth failed so client stayed nil; connection idle-timed out and reconnect failed; provisioner ran before bastion/networking was ready.

Related errors


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