{"record":{"id":"8d8183d390a95c7f","repo":"netbirdio/netbird","slug":"dial-s-w","errorCode":null,"errorMessage":"dial %s: %w","messagePattern":"dial (.+?): %w","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client/cmd/ssh.go","lineNumber":542,"sourceCode":"\nfunc runSSH(ctx context.Context, addr string, cmd *cobra.Command) error {\n\ttarget := net.JoinHostPort(strings.Trim(addr, \"[]\"), strconv.Itoa(port))\n\tc, err := sshclient.Dial(ctx, target, username, sshclient.DialOptions{\n\t\tKnownHostsFile:     knownHostsFile,\n\t\tIdentityFile:       identityFile,\n\t\tDaemonAddr:         daemonAddr,\n\t\tSkipCachedToken:    skipCachedToken,\n\t\tInsecureSkipVerify: !strictHostKeyChecking,\n\t\tNoBrowser:          sshNoBrowser,\n\t})\n\n\tif err != nil {\n\t\tcmd.Printf(\"Failed to connect to %s@%s\\n\", username, target)\n\t\tcmd.Printf(\"\\nTroubleshooting steps:\\n\")\n\t\tcmd.Printf(\"  1. Check peer connectivity: netbird status -d\\n\")\n\t\tcmd.Printf(\"  2. Verify SSH server is enabled on the peer\\n\")\n\t\tcmd.Printf(\"  3. Ensure correct hostname/IP is used\\n\")\n\t\treturn fmt.Errorf(\"dial %s: %w\", target, err)\n\t}\n\n\tsshCtx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\tgo func() {\n\t\t<-sshCtx.Done()\n\t\tif err := c.Close(); err != nil {\n\t\t\tcmd.Printf(\"Error closing SSH connection: %v\\n\", err)\n\t\t}\n\t}()\n\n\tif err := startPortForwarding(sshCtx, c, cmd); err != nil {\n\t\treturn fmt.Errorf(\"start port forwarding: %w\", err)\n\t}\n\n\tif command != \"\" {\n\t\treturn executeSSHCommand(sshCtx, c, command)","sourceCodeStart":524,"sourceCodeEnd":560,"githubUrl":"https://github.com/netbirdio/netbird/blob/93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c/client/cmd/ssh.go#L524-L560","documentation":"Returned when sshclient.Dial cannot establish the NetBird SSH session to target (host:port built from the host argument and the --port flag, default 22). Dial connects through the local netbird daemon, performs management login (possibly browser-based SSO), fetches the peer's key via the daemon, verifies it against known_hosts, and establishes the SSH transport — any failure in that chain surfaces here.","triggerScenarios":"`netbird ssh <host>` when the peer is offline or unreachable over the overlay, the SSH server is not enabled on the remote peer (management setting), the host/IP is wrong, the local daemon is not running (unix socket / npipe unreachable), login to management fails or the browser flow is cancelled, or strict host key checking rejects an unknown/changed key.","commonSituations":"Peers that connected hours ago but dropped (NAT timeout, machine asleep); SSH disabled in the peer's group policy; first connection with StrictHostKeyChecking rejecting an unseen host key; running ssh before `netbird up`; expired management session with NoBrowser set in a headless script.","solutions":["Check peer connectivity first: `netbird status -d` and confirm the peer shows Connected and SSH enabled.","Verify the target hostname/IP and port: resolve the peer's NetBird IP or hostname, and pass --port if the remote SSH server is not on 22.","Ensure the local netbird daemon/service is running (`systemctl status netbird` or check the service) and that you are logged in (`netbird login status-check`).","On first connect to a new peer, let the key be recorded or explicitly relax checking once with --insecure-on-host-key-mismatch / the documented non-strict flag; never leave it relaxed permanently.","Retry after confirming management shows the peer online; transient overlay drops usually clear within a renegotiation interval."],"exampleFix":"# before\nnetbird ssh peer-host\n# -> dial peer-host:22: <underlying cause>\n\n# after\nnetbird status -d            # confirm peer is Connected, ssh enabled\nnetbird ssh --port 22 peer-host  # re-run once peer is reachable\n# if the key is unknown/stale, refresh known hosts per docs instead of skipping verification","handlingStrategy":"retry","validationCode":"// pre-flight: daemon reachable, peer known, target resolvable\nfunc sshPreFlight(host string, port int) error {\n\tif _, err := nbclient.Status(ctx); err != nil {\n\t\treturn fmt.Errorf(\"netbird daemon down: %w\", err) // start service first\n\t}\n\tpeer := findPeerByFqdnOrIP(host) // via status -d data\n\tif peer == nil || !peer.Connected {\n\t\treturn fmt.Errorf(\"peer %s offline or unknown\", host)\n\t}\n\tif port < 1 || port > 65535 {\n\t\treturn fmt.Errorf(\"bad port %d\", port)\n\t}\n\treturn nil\n}","typeGuard":null,"tryCatchPattern":"var netErr net.Error\nif errors.As(err, &netErr) && netErr.Timeout() {\n\t// transient overlay drop: retry with backoff (1s, 5s) before giving up\n}\nif strings.Contains(err.Error(), \"knownhosts\") || strings.Contains(err.Error(), \"host key\") {\n\t// identity problem: surface to the user, do NOT auto-disable verification\n}","preventionTips":["Script a status check (`netbird status -d`) before ssh attempts; abort early on disconnected peers instead of burning a dial timeout.","Keep management sessions fresh in headless automation (service login/token) so the dial's auth leg never fails mid-batch.","Record host keys on first connect and alert on changes rather than disabling strict checking.","Wrap scripted ssh calls in a bounded retry (2-3 attempts, short backoff) for NAT-timeout flakes, but never retry auth failures blindly."],"tags":["go","network","ssh","cli","peer-connectivity"],"backgroundTag":null,"analyzedSha":"93e97f4bf1ad715072dcb3fb6cdb1763431b5a9c","analyzedAt":"2026-08-16T03:09:19.136Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}