XTLS/Xray-core · error

unknown Socks version: {version}

Error message

unknown Socks version: {version}

What it means

Returned by Handshake (proxy/socks/protocol.go:248) when the first byte of the connection is neither 0x04 (SOCKS4) nor 0x05 (SOCKS5). The server only speaks those two versions; anything else — often the first byte of HTTP ('G' 0x47, 'P' 0x50), TLS (0x16), or random data — is rejected.

Source

Thrown at proxy/socks/protocol.go:248

func (s *ServerSession) Handshake(reader io.Reader, writer net.Conn) (*protocol.RequestHeader, *TempUDPConn, error) {
	buffer := buf.StackNew()
	if _, err := buffer.ReadFullFrom(reader, 2); err != nil {
		buffer.Release()
		return nil, nil, errors.New("insufficient header").Base(err)
	}

	version := buffer.Byte(0)
	cmd := buffer.Byte(1)
	buffer.Release()

	switch version {
	case socks4Version:
		header, err := s.handshake4(cmd, reader, writer)
		return header, nil, err
	case socks5Version:
		return s.handshake5(cmd, reader, writer)
	default:
		return nil, nil, errors.New("unknown Socks version: ", version)
	}
}

// ReadUsernamePassword reads Socks 5 username/password message from the given reader.
// +----+------+----------+------+----------+
// |VER | ULEN |  UNAME   | PLEN |  PASSWD  |
// +----+------+----------+------+----------+
// | 1  |  1   | 1 to 255 |  1   | 1 to 255 |
// +----+------+----------+------+----------+
func ReadUsernamePassword(reader io.Reader) (string, string, error) {
	buffer := buf.StackNew()
	defer buffer.Release()

	if _, err := buffer.ReadFullFrom(reader, 2); err != nil {
		return "", "", err
	}
	nUsername := int32(buffer.Byte(1))

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Point SOCKS-speaking clients at the port: curl -x socks5h://host:port, or configure the app's proxy type to SOCKS5.
  2. If the traffic is actually HTTP, add an http inbound on that port instead of socks.
  3. If the traffic is another protocol, expose the matching inbound (vless/shadowsocks/etc.) on the right port.

Example fix

# before: HTTP-proxy style request against a SOCKS inbound
curl -x http://127.0.0.1:1080 https://example.com

# after: SOCKS5 with remote DNS resolution
curl -x socks5h://127.0.0.1:1080 https://example.com
Defensive patterns

Strategy: validation

Validate before calling

// Dispatch on the first wire byte before SOCKS parsing
b := make([]byte, 1)
if _, err := io.ReadFull(conn, b); err != nil { return err }
switch b[0] {
case 0x04, 0x05:
    // continue with SOCKS handshake
default:
    return fmt.Errorf("not a SOCKS connection (first byte 0x%02X); check protocol/port mapping", b[0])
}

Try / catch

if err != nil && strings.Contains(err.Error(), "unknown Socks version") {
    return fmt.Errorf("protocol mismatch on SOCKS port: client is not speaking SOCKS4/5")
}

Prevention

When it happens

Trigger: An HTTP client pointed at the SOCKS port (curl http://host:1080 uses HTTP proxy semantics, not SOCKS); HTTPS/TLS handshake bytes; a shadowsocks/vless client connected to a socks inbound; garbage probes.

Common situations: Using curl without the socks5h:// scheme (falls back to HTTP CONNECT against a SOCKS port); mixing up inbound protocols in the port map; tools defaulting to HTTP proxy mode.

Related errors


AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15). Data as JSON: /api/errors/b25b7b50a315ec65. Report an issue: GitHub.