kubernetes/kops · error

creating ssh session: %w

Error message

creating ssh session: %w

What it means

After forwarding the agent, Dial opens an SSH session on the bastion connection with client.NewSession(); failure is reported to the finished channel wrapped with this message. The error means the SSH client connection exists but a new session channel could not be created — usually because the connection dropped or the server rejected the session.

Source

Thrown at pkg/dump/dumper.go:712

	var client *ssh.Client
	finished := make(chan error)
	go func() {
		c, chans, reqs, err := ssh.NewClientConn(conn, addr, f.sshConfig)
		if err == nil {
			client = ssh.NewClient(c, chans, reqs)
			if useBastion {
				err = agent.ForwardToAgent(client, f.keyRing)
				if err != nil {
					err = fmt.Errorf("forwarding ssh auth to keyring: %w", err)
				}
			}
		}

		if err == nil && useBastion {
			session, err := client.NewSession()
			if err != nil {
				finished <- fmt.Errorf("creating ssh session: %w", err)
				return
			}
			defer session.Close()

			err = agent.RequestAgentForwarding(session)
			if err != nil {
				finished <- fmt.Errorf("requesting agent forwarding: %w", err)
				return
			}
		}

		finished <- err
	}()

	select {
	case <-ctx.Done():
		klog.Infof("cancelling SSH tcp connection due to context completion")
		conn.Close() // Close the TCP connection to force cancellation

View on GitHub (pinned to 4c8573c808)

Solutions

  1. Retry the Dial after confirming the bastion is healthy (ssh user@bastion works)
  2. Reduce concurrent SSH sessions to the bastion or raise sshd MaxSessions on the bastion host
  3. Check bastion sshd logs and instance state; recreate the bastion instance if it is wedged
  4. Increase context timeout / add backoff-retry around the dump operation for transient drops

Example fix

// before
client, err := factory.Dial(ctx, host, true)

// after
var client sshClient
err = wait.PollImmediate(5*time.Second, 2*time.Minute, func() (bool, error) {
	var e error
	client, e = factory.Dial(ctx, host, true)
	return e == nil, nil
})
Defensive patterns

Strategy: retry

Validate before calling

var ok bool
for i := 0; i < 3; i++ {
	c, e := net.DialTimeout("tcp", net.JoinHostPort(bastion, "22"), 3*time.Second)
	if e == nil {
		c.Close()
		ok = true
		break
	}
	time.Sleep(2 * time.Second)
}
if !ok {
	return fmt.Errorf("bastion %s not accepting sessions", bastion)
}

Type guard

func isSessionError(err error) bool { return strings.Contains(err.Error(), "creating ssh session") }

Try / catch

client, err := factory.Dial(ctx, host, true)
if err != nil && strings.Contains(err.Error(), "creating ssh session") {
	// transient: back off and retry
	time.Sleep(5 * time.Second)
	client, err = factory.Dial(ctx, host, true)
}

Prevention

When it happens

Trigger: client.NewSession() fails inside the Dial goroutine when useBastion=true, after ForwardToAgent succeeded — connection to bastion reset/closed, server-side session limits (MaxSessions), or server refusing new channels.

Common situations: Bastion sshd hitting MaxSessions limits during concurrent dumps; bastion restarting mid-dump; sshd config restricting session channels; transient network interruption right after handshake.

Related errors


AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05). Data as JSON: /api/errors/b22ff54cf39880ae. Report an issue: GitHub.