XTLS/Xray-core · error · errors.Error
negotiated unsupported application layer protocol: {nextProt
Error message
negotiated unsupported application layer protocol: {nextProto} What it means
After establishing the transport to the HTTP proxy, the client switches on the negotiated ALPN nextProto. Only "h2" and ""/"http/1.1" are handled; any other negotiated protocol (e.g. "h3", experimental strings from a TLS-terminating middlebox) falls into default and this error is returned.
Source
Thrown at proxy/http/client.go:348
if err != nil {
rawConn.Close()
return nil, err
}
cachedH2Mutex.Lock()
if cachedH2Conns == nil {
cachedH2Conns = make(map[net.Destination]h2Conn)
}
cachedH2Conns[dest] = h2Conn{
rawConn: rawConn,
h2Conn: h2clientConn,
}
cachedH2Mutex.Unlock()
return proxyConn, err
default:
return nil, errors.New("negotiated unsupported application layer protocol: " + nextProto)
}
}
func newHTTP2Conn(c net.Conn, pipedReqBody *io.PipeWriter, respBody io.ReadCloser) net.Conn {
return &http2Conn{Conn: c, in: pipedReqBody, out: respBody}
}
type http2Conn struct {
net.Conn
in *io.PipeWriter
out io.ReadCloser
}
func (h *http2Conn) Read(p []byte) (n int, err error) {
return h.out.Read(p)
}
func (h *http2Conn) Write(p []byte) (n int, err error) {View on GitHub (pinned to 7d214f8b09)
Solutions
- Restrict streamSettings.tlsSettings.alpn to ["h2", "http/1.1"] for the HTTP outbound
- Ensure you are actually talking to the HTTP proxy, not a CDN endpoint that negotiates other protocols
- Upgrade Xray if a newer build supports additional protocols on this path
- Check for TLS-intercepting middleboxes rewriting ALPN
Example fix
// before
"streamSettings": { "tlsSettings": { "alpn": ["h3"] } }
// after
"streamSettings": { "tlsSettings": { "alpn": ["h2", "http/1.1"] } } Defensive patterns
Strategy: validation
Validate before calling
```go
allowed := map[string]bool{"h2": true, "http/1.1": true, "": true}
if state, ok := tls ConnectionState(); ok && !allowed[state.NegotiatedProtocol] {
// fix alpn config before the outbound trips the default case
}
``` Type guard
```go
func supportedALPN(proto string) bool {
return proto == "" || proto == "h2" || proto == "http/1.1"
}
``` Prevention
- Pin tlsSettings.alpn to ["h2","http/1.1"] for HTTP outbounds
- Point the outbound directly at the proxy, not a CDN edge
- Re-check ALPN config after upgrades
When it happens
Trigger: settings.servers[].tls enabled (or stream TLS to the proxy) where the TLS endpoint negotiates something other than h2 or http/1.1 — custom ALPN lists in streamSettings.tlsSettings.alpn, h3-capable proxies, or an intercepting box injecting unexpected protocols.
Common situations: User sets tlsSettings.alpn to ["h3"] or ["h2","h3"] for an HTTP outbound; a CDN/LB in front of the proxy negotiating its preferred proto; older Xray builds without some proto support.
Related errors
- failed to produce report
- Failed to build TLS config.
- REALITY only supports RAW, XHTTP and gRPC for now.
- Unknown security "" + c.Security + "".
- no target server found
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/caa0eed8e4bf3263.
Report an issue: GitHub.