nodejs/node · error · SocketError

UND_ERR_SOCKET

UND_ERR_SOCKET

Error message

bad connect

What it means

Thrown as a SocketError (code UND_ERR_SOCKET) by ConnectHandler.onResponseStart. undici.connect issues an HTTP CONNECT request expecting a 101 Switching Protocols upgrade (handled by onRequestUpgrade). If the server responds with a normal HTTP response instead of an upgrade, onResponseStart fires and undici throws 'bad connect' — the tunnel was never established. This is a protocol/server-level failure, not an argument error.

Source

Thrown at deps/undici/src/lib/api/api-connect.js:48

    this.abort = null

    addSignal(this, signal)
  }

  onRequestStart (controller, context) {
    if (this.reason) {
      controller.abort(this.reason)
      return
    }

    assert(this.callback)

    this.abort = (reason) => controller.abort(reason)
    this.context = context
  }

  onResponseStart () {
    throw new SocketError('bad connect', null)
  }

  onRequestUpgrade (controller, statusCode, headers, socket) {
    const { callback, opaque, context } = this

    removeSignal(this)

    this.callback = null

    let responseHeaders = headers
    const rawHeaders = controller?.rawHeaders
    // Indicates is an HTTP2Session
    if (responseHeaders != null) {
      responseHeaders = this.responseHeaders === 'raw'
        ? util.parseRawHeaders(rawHeaders)
        : headers
    }

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Point connect() at an HTTP proxy that supports CONNECT, not directly at the origin server.
  2. If a proxy is required, authenticate via Proxy-Authorization or configure allowlisting on the proxy.
  3. For raw TLS to an origin, use undici request/stream with an https URL or a dedicated Client instead of connect().
  4. Inspect the response status/headers from the intermediary to diagnose the refused tunnel.

Example fix

// before: connecting directly to origin (no CONNECT support)
undici.connect({ path: 'api.example.com:443' }, cb)   // server returns 200 -> 'bad connect'
// after: tunnel through a CONNECT-capable proxy
undici.connect({ path: 'api.example.com:443', dispatcher: new undici.ProxyAgent('http://proxy:3128') }, cb)
Defensive patterns

Strategy: try-catch

Try / catch

undici.connect({ path: target, dispatcher: proxyAgent }, (err, { socket }) => {
  if (err && err.code === 'UND_ERR_SOCKET' && /bad connect/.test(err.message)) {
    console.error('CONNECT rejected by upstream — point connect() at a CONNECT-capable proxy')
    return
  }
  if (err) throw err
  // use socket
})

Prevention

When it happens

Trigger: Calling undici.connect against a target that does not support CONNECT tunneling: the upstream returned a regular HTTP response (200/4xx/5xx) instead of a 101 upgrade. Common when connecting directly to an origin server (not a proxy), or when a proxy refuses the CONNECT (e.g. 407 auth required, 403 forbidden).

Common situations: Using connect() as if it were a raw TCP socket to an origin (it requires a proxy that speaks CONNECT); proxy requires auth/allowlist not configured; TLS origin rejecting CONNECT; intermediary (corporate proxy/firewall) returning an HTML error page.

Related errors


AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13). Data as JSON: /api/errors/b69998f19590fcd0. Report an issue: GitHub.