netbirdio/netbird · error
dial context: %w
Error message
dial context: %w
What it means
CreateConnection failed at grpc.DialContext. Because the dial uses grpc.WithBlock and a 30-second context timeout, the returned error is whatever blocked the connection until the deadline: context.DeadlineExceeded when the server never became reachable, or transport-level failures such as connection refused, TLS x509 verification errors (certificate not trusted by the system pool or the embedded fallback roots), or DNS resolution failures from the custom dialer. The %w wrap preserves the gRPC cause for errors.Is/As inspection.
Source
Thrown at client/grpc/dialer.go:62
}
connCtx, cancel := context.WithTimeout(ctx, 30*time.Second)
defer cancel()
opts := []grpc.DialOption{
transportOption,
WithCustomDialer(tlsEnabled, component),
grpc.WithBlock(),
grpc.WithKeepaliveParams(keepalive.ClientParameters{
Time: 30 * time.Second,
Timeout: 10 * time.Second,
}),
}
opts = append(opts, extraOpts...)
conn, err := grpc.DialContext(connCtx, addr, opts...)
if err != nil {
return nil, fmt.Errorf("dial context: %w", err)
}
return conn, nil
}
View on GitHub (pinned to 93e97f4bf1)
Solutions
- Check the wrapped error class first: errors.Is(err, context.DeadlineExceeded) means unreachable, x509 errors mean trust, connection refused means port/service
- Verify the service is listening on the configured address and the URL scheme/port match the deployment (443 vs custom)
- Install the CA on the client OS trust store or serve a publicly-trusted certificate so SystemCertPool validates it
- Test basic reachability outside the app (openssl s_client, curl, nc) to isolate TLS vs network vs DNS
- Retry with backoff for transient outages; the fixed 30s WithBlock window is not tunable by callers
Example fix
// before
conn, err := grpc.CreateConnection(ctx, addr, true, "/management")
if err != nil { return err }
// after
conn, err := grpc.CreateConnection(ctx, addr, true, "/management")
if err != nil {
if errors.Is(err, context.DeadlineExceeded) {
return fmt.Errorf("management unreachable at %s: %w", addr, err)
}
return fmt.Errorf("connect management: %w", err)
} Defensive patterns
Strategy: retry
Validate before calling
// preflight outside the app before dialing
// nc -vz host 443 / openssl s_client -connect host:443
u, err := url.Parse(addr)
if err != nil || u.Host == "" {
return fmt.Errorf("invalid service address %q", addr)
} Type guard
func reachableAddr(addr string) bool {
u, err := url.Parse(addr)
return err == nil && u.Host != "" && u.Port() != ""
} Try / catch
var conn *grpc.ClientConn
err := backoff.Retry(func() error {
c, e := grpc.CreateConnection(ctx, addr, tlsEnabled, "/management")
if e != nil {
if errors.Is(e, context.DeadlineExceeded) || isTemporary(e) {
return e // retry with backoff
}
return backoff.Permanent(e) // TLS trust / config: fix, don't retry
}
conn = c
return nil
}, grpc.Backoff(ctx)) Prevention
- Install the server CA into the OS trust store or serve a publicly trusted certificate
- Validate the management/signal URL shape before first connect
- Distinguish permanent causes (x509, refused) from transient (deadline) and only retry the latter
- Monitor dial failures: persistent DeadlineExceeded usually means a firewall or DNS problem, not slowness
When it happens
Trigger: Management or signal service down or unreachable at addr; wrong host/port in the configuration; TLS enabled against a server whose certificate chain is not in SystemCertPool nor the embedded roots; a custom dialer/proxy path (WebSocket component like /management or /signal) failing; network offline or DNS broken so WithBlock exhausts the 30s window.
Common situations: Self-hosted NetBird with a self-signed or privately-signed CA not installed on the client host; typo'd management URL; firewall blocking the gRPC port; the 30s dial timeout being too short on high-latency or proxy-chained networks; system cert pool unavailable on stripped-down containers causing fallback roots that do not trust the server.
Related errors
- domain is required for TLS services (used for SNI matching)
- auth is not supported for TLS services
- listen_port is required for TLS services
- TLS services must have exactly one target
- session_idle_timeout must be positive for L4 services
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/0918b704e78812a5.
Report an issue: GitHub.