golang/go · error
tls: server sent an unexpected quic_transport_parameters ext
Error message
tls: server sent an unexpected quic_transport_parameters extension
What it means
Mirror of 630: when the connection is NOT in QUIC mode (c.quic == nil), EncryptedExtensions must NOT carry quic_transport_parameters. Go sends `unsupported_extension` if it does. Indicates a regular TLS 1.3 server incorrectly emitting a QUIC-only extension.
Source
Thrown at src/crypto/tls/handshake_client_tls13.go:557
// does not specify how clients handle the selection of an incompatible protocol.
// RFC 9001 Section 8.1 specifies that QUIC clients send no_application_protocol
// in this case. Always sending no_application_protocol seems reasonable.
c.sendAlert(alertNoApplicationProtocol)
return err
}
c.clientProtocol = encryptedExtensions.alpnProtocol
if c.quic != nil {
if encryptedExtensions.quicTransportParameters == nil {
// RFC 9001 Section 8.2.
c.sendAlert(alertMissingExtension)
return errors.New("tls: server did not send a quic_transport_parameters extension")
}
c.quicSetTransportParameters(encryptedExtensions.quicTransportParameters)
} else {
if encryptedExtensions.quicTransportParameters != nil {
c.sendAlert(alertUnsupportedExtension)
return errors.New("tls: server sent an unexpected quic_transport_parameters extension")
}
}
if !hs.hello.earlyData && encryptedExtensions.earlyData {
c.sendAlert(alertUnsupportedExtension)
return errors.New("tls: server sent an unexpected early_data extension")
}
if hs.hello.earlyData && !encryptedExtensions.earlyData {
c.quicRejectedEarlyData()
}
if encryptedExtensions.earlyData {
if hs.session.cipherSuite != c.cipherSuite {
c.sendAlert(alertHandshakeFailure)
return errors.New("tls: server accepted 0-RTT with the wrong cipher suite")
}
if hs.session.alpnProtocol != c.clientProtocol {
c.sendAlert(alertHandshakeFailure)
return errors.New("tls: server accepted 0-RTT with the wrong ALPN")View on GitHub (pinned to b6b368adc5)
Solutions
- Report to the server operator — the extension is QUIC-only.
- Capture the EncryptedExtensions to confirm the unexpected extension is server-origin.
- Test the same hostname over a known client (openssl s_client) to cross-check.
- Patch the server to only emit the extension on QUIC transports.
Defensive patterns
Strategy: validation
Validate before calling
// Pre-flight: ensure you are not accidentally enabling QUIC mode for a TCP connection. // QUIC mode is set by the QUIC library via non-exported hooks; using tls.Dial keeps c.quic == nil. // If you see this error, the server is at fault — no client-side prevention.
Try / catch
if err := conn.Handshake(); err != nil {
if strings.Contains(err.Error(), "unexpected quic_transport_parameters") {
log.Printf("server %s emitted a QUIC-only extension over TCP", addr)
}
return err
} Prevention
- Report servers that emit QUIC-only extensions over TCP.
- Packet-capture to confirm the extension origin.
- Cross-check with openssl s_client.
When it happens
Trigger: Standard tls.Dial/tls.Client handshake where the server's EncryptedExtensions includes quic_transport_parameters. c.quic is nil because the caller did not enable QUIC mode.
Common situations: Server that always sends quic_transport_parameters regardless of transport, a misconfigured proxy, or a TLS library bug on the server. Should not occur against compliant servers.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- tls: server did not send a quic_transport_parameters extensi
- tls: server sent encrypted client hello retry configs after
- tls: server sent two HelloRetryRequest messages
- tls: server sent a cookie in a normal ServerHello
- tls: malformed key_share extension
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/128c38ed7525def2.
Report an issue: GitHub.