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
- Inspect getReplyErrorMessage(rep) to map the code to a cause (e.g. 0x04=host unreachable, 0x05=connection refused).
- Verify the target host resolves and is reachable from the proxy's network, not just yours.
- Use socks5h:// to force remote DNS resolution by the proxy.
- 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
- Use socks5h:// so the proxy does remote DNS.
- Verify the target is reachable from the proxy's network.
- Map the REP code to decide retry vs fail-fast.
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
- UND_ERR_SOCKS5_VERSION
- UND_ERR_SOCKS5_AUTH_REJECTED
- UND_ERR_SOCKS5_AUTH_FAILED
- UND_ERR_SOCKS5_REPLY_VERSION
- UND_ERR_SOCKS5_ADDR_TYPE
AI-assisted analysis of nodejs/node@1b2de5e052 (2026-08-13).
Data as JSON: /api/errors/a6ac27ba0c6320e3.
Report an issue: GitHub.