{"record":{"id":"f0d8a72dabfd8887","repo":"kovidgoyal/kitty","slug":"failed-to-connect-to-s-s-with-error-w","errorCode":null,"errorMessage":"Failed to connect to %s:%s with error: %w","messagePattern":"Failed to connect to (.+?):(.+?) with error: %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tools/cmd/at/socket_io.go","lineNumber":180,"sourceCode":"\nfunc do_socket_io(io_data *rc_io_data) (serialized_response []byte, err error) {\n\tvar conn net.Conn\n\tif global_options.to_network == \"fd\" {\n\t\tfd, _ := strconv.Atoi(global_options.to_address)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tf := os.NewFile(uintptr(fd), \"fd:\"+global_options.to_address)\n\t\tconn, err = net.FileConn(f)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"Failed to open a socket for the remote control file descriptor: %d with error: %w\", fd, err)\n\t\t}\n\t\tdefer f.Close()\n\t} else {\n\t\tnetwork := utils.IfElse(global_options.to_network == \"ip\", \"tcp\", global_options.to_network)\n\t\tconn, err = net.Dial(network, global_options.to_address)\n\t\tif err != nil {\n\t\t\terr = fmt.Errorf(\"Failed to connect to %s:%s with error: %w\", network, global_options.to_address, err)\n\t\t\treturn\n\t\t}\n\t}\n\tdefer conn.Close()\n\treturn simple_socket_io(&conn, io_data)\n}\n","sourceCodeStart":162,"sourceCodeEnd":187,"githubUrl":"https://github.com/kovidgoyal/kitty/blob/6d5d0c440603ad9bdf6dcd599f73f6dde21acb44/tools/cmd/at/socket_io.go#L162-L187","documentation":"net.Dial failed while connecting to the target network/address. The underlying error (wrapped with %w) says whether it was DNS resolution, connection refused, timeout, or network unreachable. This is the standard TCP/Unix dial failure path when fd passthrough mode is not in use.","triggerScenarios":"Calling do_socket_io with to_network 'ip' (mapped to tcp) or another network and an address nothing is listening on, a hostname that doesn't resolve, a firewall dropping SYN packets (timeout), or the listener process not yet started.","commonSituations":"Service not started yet, wrong port in config, DNS pointing at a dead host, firewall/VPN blocking the port, or IPv6/IPv4 mismatch between resolved address and listener binding.","solutions":["Check the wrapped error: 'connection refused' means nothing is listening — start the peer or fix the port; 'no such host' means fix DNS; 'i/o timeout' means firewall/routing","Verify the address format matches the network (host:port for tcp/ip, path for unix)","Test reachability with nc/curl or telnet to the same address","If it's a startup-order issue, retry with backoff or add a readiness check before dialing"],"exampleFix":"# before\nat --to ip:myhost:9999\n# after: confirm listener is up first\nss -ltnp | grep 9999   # then retry, or use the exact host:port it shows\nat --to ip:127.0.0.1:9999","handlingStrategy":"retry","validationCode":"// Pre-flight: is anything listening?\nif _, err := net.DialTimeout(\"tcp\", addr, 2*time.Second); err != nil {\n    log.Fatalf(\"peer %s unreachable: %v\", addr, err)\n}","typeGuard":null,"tryCatchPattern":"var conn net.Conn\nfor attempt := 0; attempt < 5; attempt++ {\n    conn, err = doSocketIO(opts)\n    if err == nil { break }\n    if !isTemporary(err) { break } // refused/timeout -> retry; DNS error -> fail fast\n    time.Sleep(time.Duration(attempt+1) * 500 * time.Millisecond)\n}","preventionTips":["Start listeners before dialers, or add readiness checks in startup scripts","Wrap dials with net.DialTimeout instead of unbounded waits","Use errors.Is/As on the wrapped error to distinguish refused vs timeout vs DNS"],"tags":["network","connection-refused","tcp","go"],"backgroundTag":"connection-refused","analyzedSha":"6d5d0c440603ad9bdf6dcd599f73f6dde21acb44","analyzedAt":"2026-08-27T14:20:20.142Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}