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
- Point SOCKS-speaking clients at the port: curl -x socks5h://host:port, or configure the app's proxy type to SOCKS5.
- If the traffic is actually HTTP, add an http inbound on that port instead of socks.
- 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
- Use socks5h:// scheme in curl and SOCKS type in app proxy settings.
- Keep a port/protocol map of all inbounds to avoid cross-connections.
- Prefer routing by separate loopback ports per protocol in tests.
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
- socks 4 is not allowed when auth is required.
- unknown config id:
- SOCKS servers: "users" should have one member at most. Multi
- failed to parse Socks user
- failed to parse socks account
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/b25b7b50a315ec65.
Report an issue: GitHub.