kubernetes/kops · error
error dialing tcp %s: %w
Error message
error dialing tcp %s: %w
What it means
Dial wraps the error from net.Dialer.DialContext with this message when the initial TCP connection to host:22 (or bastion:22) fails. The wrapped %w error is the underlying net error (timeout, connection refused, no route to host, DNS failure). The library uses a 5-second dial timeout, so slow/unreachable hosts surface as i/o timeout.
Source
Thrown at pkg/dump/dumper.go:690
func (f *sshClientFactoryImplementation) Dial(ctx context.Context, host string, useBastion bool) (sshClient, error) {
addr := host
if useBastion {
if f.bastion == "" {
return nil, fmt.Errorf("bastion is not set, but useBastion is true")
}
addr = f.bastion
}
if addr == "" {
return nil, fmt.Errorf("host is empty")
}
addr = net.JoinHostPort(addr, "22")
d := net.Dialer{
Timeout: 5 * time.Second,
}
conn, err := d.DialContext(ctx, "tcp", addr)
if err != nil {
return nil, fmt.Errorf("error dialing tcp %s: %w", addr, err)
}
// We have a TCP connection; we will force-close it to support context cancellation
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)
}
}
}
View on GitHub (pinned to 4c8573c808)
Solutions
- Check network reachability: open port 22 in the security group / firewall for your source IP, or run the dump from within the VPC
- Verify the target host/bastion instance is running and its recorded IP/DNS is current (kops get instances / cloud console)
- If a bastion is required, confirm it is up and Dial is being called with useBastion=true and a valid bastion address
- Inspect the wrapped error in the message to distinguish timeout vs connection refused vs DNS failure and act accordingly
Example fix
// before (host unreachable directly) client, err := factory.Dial(ctx, privateNodeIP, false) // after (route via bastion) client, err := factory.Dial(ctx, privateNodeIP, factory.HasBastion())
Defensive patterns
Strategy: retry
Validate before calling
conn, err := net.DialTimeout("tcp", net.JoinHostPort(host, "22"), 3*time.Second)
if err != nil {
return fmt.Errorf("host %s unreachable on tcp/22 before dump: %w", host, err)
}
conn.Close() Type guard
func isDialError(err error) bool { return strings.Contains(err.Error(), "error dialing tcp") } Try / catch
client, err := factory.Dial(ctx, host, useBastion)
if err != nil {
var netErr net.Error
if strings.Contains(err.Error(), "error dialing tcp") && errors.As(err, &netErr) {
return fmt.Errorf("check security groups allow tcp/22 to %s: %w", host, err)
}
return err
} Prevention
- Pre-flight check tcp/22 reachability before running dumps
- Ensure security groups/firewalls permit SSH from your network or run inside the VPC
- Use the bastion path for private-subnet nodes
- Increase context timeout for slow links
When it happens
Trigger: TCP dial to addr (net.JoinHostPort(host, "22") or bastion:22) fails: security group blocks port 22, host is down/terminated, DNS name unresolvable, 5s timeout exceeded, or wrong IP recorded for the instance.
Common situations: AWS security groups not allowing SSH from the operator's network; dumping a cluster where nodes are in private subnets and neither direct SSH nor the bastion is reachable; bastion instance stopped; stale DNS or IP after node replacement.
Understand the failure class
Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.
Related errors
- failed to SSH to %q (with user %q): %w
- failed to start SSH session: %w
- connecting: %w
- unable to SSH to %q: %v
- error executing command %q: %v
AI-assisted analysis of kubernetes/kops@4c8573c808 (2026-09-05).
Data as JSON: /api/errors/2d964c8fc18b0be0.
Report an issue: GitHub.