netbirdio/netbird · error
dial %s: %w
Error message
dial %s: %w
What it means
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.
Source
Thrown at client/cmd/ssh.go:542
func runSSH(ctx context.Context, addr string, cmd *cobra.Command) error {
target := net.JoinHostPort(strings.Trim(addr, "[]"), strconv.Itoa(port))
c, err := sshclient.Dial(ctx, target, username, sshclient.DialOptions{
KnownHostsFile: knownHostsFile,
IdentityFile: identityFile,
DaemonAddr: daemonAddr,
SkipCachedToken: skipCachedToken,
InsecureSkipVerify: !strictHostKeyChecking,
NoBrowser: sshNoBrowser,
})
if err != nil {
cmd.Printf("Failed to connect to %s@%s\n", username, target)
cmd.Printf("\nTroubleshooting steps:\n")
cmd.Printf(" 1. Check peer connectivity: netbird status -d\n")
cmd.Printf(" 2. Verify SSH server is enabled on the peer\n")
cmd.Printf(" 3. Ensure correct hostname/IP is used\n")
return fmt.Errorf("dial %s: %w", target, err)
}
sshCtx, cancel := context.WithCancel(ctx)
defer cancel()
go func() {
<-sshCtx.Done()
if err := c.Close(); err != nil {
cmd.Printf("Error closing SSH connection: %v\n", err)
}
}()
if err := startPortForwarding(sshCtx, c, cmd); err != nil {
return fmt.Errorf("start port forwarding: %w", err)
}
if command != "" {
return executeSSHCommand(sshCtx, c, command)View on GitHub (pinned to 93e97f4bf1)
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.
Example fix
# before netbird ssh peer-host # -> dial peer-host:22: <underlying cause> # after netbird status -d # confirm peer is Connected, ssh enabled netbird ssh --port 22 peer-host # re-run once peer is reachable # if the key is unknown/stale, refresh known hosts per docs instead of skipping verification
Defensive patterns
Strategy: retry
Validate before calling
// pre-flight: daemon reachable, peer known, target resolvable
func sshPreFlight(host string, port int) error {
if _, err := nbclient.Status(ctx); err != nil {
return fmt.Errorf("netbird daemon down: %w", err) // start service first
}
peer := findPeerByFqdnOrIP(host) // via status -d data
if peer == nil || !peer.Connected {
return fmt.Errorf("peer %s offline or unknown", host)
}
if port < 1 || port > 65535 {
return fmt.Errorf("bad port %d", port)
}
return nil
} Try / catch
var netErr net.Error
if errors.As(err, &netErr) && netErr.Timeout() {
// transient overlay drop: retry with backoff (1s, 5s) before giving up
}
if strings.Contains(err.Error(), "knownhosts") || strings.Contains(err.Error(), "host key") {
// identity problem: surface to the user, do NOT auto-disable verification
} Prevention
- 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.
When it happens
Trigger: `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.
Common situations: 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.
Related errors
- start port forwarding: %w
- execute command: %w
- open terminal: %w
- local port forward %s: %w
- remote port forward %s: %w
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/8d8183d390a95c7f.
Report an issue: GitHub.