nodejs/node · error · Socks5ProxyError

UND_ERR_SOCKS5_REPLY_${reply}

UND_ERR_SOCKS5_REPLY_${reply}

Error message

SOCKS5 connection failed: ${errorMessage}

What it means

Thrown in handleConnectResponse() when the REP (reply code) is not REPLY_CODES.SUCCEEDED (0x00). The proxy itself received the CONNECT but could not establish the target connection (e.g. host unreachable, connection refused, TTL expired, command not supported). The dynamic error code is UND_ERR_SOCKS5_REPLY_<rep>.

Source

Thrown at deps/undici/src/lib/core/socks5-client.js:352

      responseLength += 4 + 2 // IPv4 + port
    } else if (addressType === ADDRESS_TYPES.DOMAIN) {
      if (this.buffer.length < 5) {
        return // Need domain length byte
      }
      responseLength += 1 + this.buffer[4] + 2 // length byte + domain + port
    } else if (addressType === ADDRESS_TYPES.IPV6) {
      responseLength += 16 + 2 // IPv6 + port
    } else {
      throw new Socks5ProxyError(`Invalid address type in reply: ${addressType}`, 'UND_ERR_SOCKS5_ADDR_TYPE')
    }

    if (this.buffer.length < responseLength) {
      return // Not enough data for full response
    }

    if (reply !== REPLY_CODES.SUCCEEDED) {
      const errorMessage = this.getReplyErrorMessage(reply)
      throw new Socks5ProxyError(`SOCKS5 connection failed: ${errorMessage}`, `UND_ERR_SOCKS5_REPLY_${reply}`)
    }

    // Parse bound address and port
    let boundAddress
    let offset = 4

    if (addressType === ADDRESS_TYPES.IPV4) {
      boundAddress = Array.from(this.buffer.subarray(offset, offset + 4)).join('.')
      offset += 4
    } else if (addressType === ADDRESS_TYPES.DOMAIN) {
      const domainLength = this.buffer[offset]
      offset += 1
      boundAddress = this.buffer.subarray(offset, offset + domainLength).toString()
      offset += domainLength
    } else if (addressType === ADDRESS_TYPES.IPV6) {
      // Parse IPv6 address from 16-byte buffer
      const parts = []
      for (let i = 0; i < 8; i++) {

View on GitHub (pinned to 1b2de5e052)

Solutions

  1. Inspect getReplyErrorMessage(rep) to map the code to a cause (e.g. 0x04=host unreachable, 0x05=connection refused).
  2. Verify the target host resolves and is reachable from the proxy's network, not just yours.
  3. Use socks5h:// to force remote DNS resolution by the proxy.
  4. Retry with backoff for transient codes; fix the target address for permanent ones.

Example fix

// before
proxy: 'socks5://proxy:1080'  // proxy can't resolve target locally

// after
proxy: 'socks5h://proxy:1080'  // proxy resolves target DNS remotely
Defensive patterns

Strategy: retry

Validate before calling

function isRetryableReply(rep) {
  // 0x03 network unreachable, 0x04 host unreachable, 0x05 connection refused, 0x06 TTL expired
  return [0x03, 0x04, 0x05, 0x06].includes(rep)
}

Try / catch

try { client.connect(host, port) } catch (e) {
  if (/^UND_ERR_SOCKS5_REPLY_/.test(e.code)) {
    const rep = Number(e.code.slice('UND_ERR_SOCKS5_REPLY_'.length))
    if (isRetryableReply(rep)) { /* backoff + retry on new client */ }
    else throw e // permanent (e.g. 0x02 not allowed, 0x07 command not supported)
  } else throw e
}

Prevention

When it happens

Trigger: Target host:port unreachable from the proxy; target refused the connection; DNS resolution failure at the proxy (with socks5 vs socks5h); proxy policy forbidding the destination; network ACL between proxy and target.

Common situations: Wrong target host/port; target service down; using socks5:// (proxy does local DNS) for a host the proxy cannot resolve, vs socks5h:// (remote DNS); firewall rules between proxy and target.

Related errors


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