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

  1. Treat as teardown noise unless it repeats for the same peer: the double-close case is already filtered via net.ErrClosed
  2. If it persists, inspect the wrapped message to identify which net.Conn implementation is failing (pion relay conn vs plain UDP)
  3. 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

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


AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16). Data as JSON: /api/errors/18589cba9a26b5d4. Report an issue: GitHub.