netbirdio/netbird · warning
remote conn: %s
Error message
remote conn: %s
What it means
Appended to the multierror returned by WGUDPProxy.close() when remoteConn.Close() fails with anything other than net.ErrClosed. The remote conn is the relay/TURN connection. net.ErrClosed is explicitly filtered, so this fires for genuine errors: socket in a bad state, close(2) returning EBADF, or a custom net.Conn implementation whose Close returns its own error (e.g. relay framing teardown failure).
Source
Thrown at client/iface/wgproxy/udp/proxy.go:191
defer p.closeMu.Unlock()
// prevent double close
if p.closed {
return nil
}
p.closeListener.SetCloseListener(nil)
p.closed = true
p.cancel()
p.pausedCond.L.Lock()
p.paused = false
p.pausedCond.Signal()
p.pausedCond.L.Unlock()
if err := p.remoteConn.Close(); err != nil && !errors.Is(err, net.ErrClosed) {
result = multierror.Append(result, fmt.Errorf("remote conn: %s", err))
}
if err := p.localConn.Close(); err != nil {
result = multierror.Append(result, fmt.Errorf("local conn: %s", err))
}
if p.srcFakerConn != nil {
if err := p.srcFakerConn.Close(); err != nil {
result = multierror.Append(result, fmt.Errorf("src faker raw conn: %s", err))
}
}
return cerrors.FormatErrorOrNil(result)
}
// proxyToRemote proxies from Wireguard to the RemoteKey
func (p *WGUDPProxy) proxyToRemote(ctx context.Context) {
defer func() {View on GitHub (pinned to 93e97f4bf1)
Solutions
- Treat as teardown noise unless it repeats for the same peer: the double-close case is already filtered via net.ErrClosed
- If it persists, inspect the wrapped message to identify which net.Conn implementation is failing (pion relay conn vs plain UDP)
- Verify fd count over time (`ls /proc/$(pgrep -x netbird)/fd | wc -l`) to rule out a leak from failed closes
Defensive patterns
Strategy: try-catch
Try / catch
if err := p.close(); err != nil {
var merr *multierror.Error
if errors.As(err, &merr) {
for _, e := range merr.Errors {
if strings.HasPrefix(e.Error(), "remote conn:") {
log.Debugf("remote conn close noise: %v", e) // teardown, socket is dead anyway
continue
}
log.Warnf("proxy close: %v", e)
}
}
} Prevention
- Rely on the built-in net.ErrClosed filter; do not pre-close the remote conn out from under the proxy
- Log close-path multierrors at debug in normal operation to keep disconnect logs readable
- Track fd counts if close errors correlate with relay churn
When it happens
Trigger: Teardown racing with the proxy loops: proxyToRemote/proxyToLocal both defer close(), and any external CloseConn call can interleave; underlying TURN conn already terminated by the relay; custom conn wrappers erroring on double cleanup.
Common situations: Seen in logs as 'error in proxy to remote loop' or returned from CloseConn during peer disconnect/reconnect cycles. Usually benign - the socket is going away anyway - but it can mask an fd leak if Close genuinely failed.
Related errors
- local conn: %s
- src faker raw conn: %s
- failed to remove WireGuard interface %s: %w
- timeout when waiting for interface %s to be removed
- proxy not started
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/18589cba9a26b5d4.
Report an issue: GitHub.