{"record":{"id":"429eae90a2c14c29","repo":"hashicorp/terraform","slug":"error-connecting-to-bastion-s","errorCode":null,"errorMessage":"Error connecting to bastion: %s","messagePattern":"Error connecting to bastion: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/communicator/ssh/communicator.go","lineNumber":861,"sourceCode":"\t\t\tpConn, err = newHttpProxyConn(p, bAddr)\n\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"Error connecting to proxy: %s\", err)\n\t\t\t}\n\n\t\t\tbConn, bChans, bReq, err = ssh.NewClientConn(pConn, bAddr, bConf)\n\n\t\t\tif err != nil {\n\t\t\t\treturn nil, fmt.Errorf(\"Error creating new client connection via proxy: %s\", err)\n\t\t\t}\n\n\t\t\tbastion = ssh.NewClient(bConn, bChans, bReq)\n\t\t} else {\n\t\t\tbastion, err = ssh.Dial(bProto, bAddr, bConf)\n\t\t}\n\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"Error connecting to bastion: %s\", err)\n\t\t}\n\n\t\tlog.Printf(\"[DEBUG] Connecting via bastion (%s) to host: %s\", bAddr, addr)\n\t\tconn, err := bastion.Dial(proto, addr)\n\t\tif err != nil {\n\t\t\tbastion.Close()\n\t\t\treturn nil, err\n\t\t}\n\n\t\t// Wrap it up so we close both things properly\n\t\treturn &bastionConn{\n\t\t\tConn:    conn,\n\t\t\tBastion: bastion,\n\t\t}, nil\n\t}\n}\n\ntype bastionConn struct {","sourceCodeStart":843,"sourceCodeEnd":879,"githubUrl":"https://github.com/hashicorp/terraform/blob/d32a084675427f5ac3f7d2868578ef8b2c1dc525/internal/communicator/ssh/communicator.go#L843-L879","documentation":"Returned when neither the proxy-via-bastion path nor the direct ssh.Dial to the bastion succeeded — the umbrella error after both branches. With a proxy configured it fires if bastion.Dial failed despite a successful NewClientConn; without a proxy it fires if the direct ssh.Dial to the bastion failed. It indicates the bastion itself is the problem, not the proxy.","triggerScenarios":"Direct (no-proxy) SSH dial to bastion_host:bastion_port failed (network, host key, auth), OR with a proxy the bastion connection opened but bastion.Dial to dial further failed. The wrapped %s gives the ssh.Dial or bastion.Dial error.","commonSituations":"bastion_host typo or wrong bastion_port; security group/ACL blocking the bastion port from the runner; bastion sshd down; host key changed; network partition to the bastion.","solutions":["Confirm network reachability to the bastion: nc -vz <bastion_host> <bastion_port>.","Verify bastion_host and bastion_port (default 22) values.","Open the security group / firewall for ingress to the bastion from the runner's IP.","Read the wrapped %s to distinguish auth failure vs connection refused vs host key mismatch."],"exampleFix":"// before\nconnection {\n  host          = \"10.0.0.5\"\n  bastion_host  = \"bastion.exmaple.com\" // typo\n  bastion_port  = 2222\n}\n\n// after\nconnection {\n  host          = \"10.0.0.5\"\n  bastion_host  = \"bastion.example.com\"\n  bastion_port  = 22\n}","handlingStrategy":"validation","validationCode":"# Verify reachability to the bastion before apply:\n#   nc -vz <bastion_host> <bastion_port>\n# Confirm security groups/firewalls allow the runner -> bastion on that port.","typeGuard":null,"tryCatchPattern":"// In Go, the umbrella bastion error wraps the actual dial failure; surface it:\nif strings.Contains(err.Error(), \"Error connecting to bastion\") {\n    return fmt.Errorf(\"bastion unreachable; check host/port/sg: %w\", err)\n}","preventionTips":["Open security group ingress to the bastion from the runner IP.","Double-check bastion_host spelling and bastion_port (default 22).","Use a known-good bastion image and confirm sshd is running."],"tags":["terraform","ssh","bastion","connection","dial","provisioner"],"backgroundTag":null,"analyzedSha":"d32a084675427f5ac3f7d2868578ef8b2c1dc525","analyzedAt":"2026-08-11T18:43:52.779Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}