golang/go · error
tls: server advertised unrequested ALPN extension
Error message
tls: server advertised unrequested ALPN extension
What it means
In checkALPN, if the server returned a non-empty ALPN value (serverProto != "") but the client sent no ALPN extension (len(clientProtos) == 0), the server invented an extension the client never offered — a protocol violation.
Source
Thrown at src/crypto/tls/handshake_client.go:979
c.scts = hs.session.scts
}
c.curveID = hs.session.curveID
return true, nil
}
// checkALPN ensure that the server's choice of ALPN protocol is compatible with
// the protocols that we advertised in the ClientHello.
func checkALPN(clientProtos []string, serverProto string, quic bool) error {
if serverProto == "" {
if quic && len(clientProtos) > 0 {
// RFC 9001, Section 8.1
return errors.New("tls: server did not select an ALPN protocol")
}
return nil
}
if len(clientProtos) == 0 {
return errors.New("tls: server advertised unrequested ALPN extension")
}
for _, proto := range clientProtos {
if proto == serverProto {
return nil
}
}
return errors.New("tls: server selected unadvertised ALPN protocol")
}
func (hs *clientHandshakeState) readFinished(out []byte) error {
c := hs.c
if err := c.readChangeCipherSpec(); err != nil {
return err
}
// finishedMsg is included in the transcript, but not until after we
// check the client version, since the state before this message wasView on GitHub (pinned to b6b368adc5)
Solutions
- If you want ALPN, set Config.NextProtos to the protocols you will accept.
- Patch the server so it does not return ALPN when the client did not offer it.
- Investigate the path for an injecting middlebox.
Example fix
// If you expect ALPN, advertise what you accept:
cfg := &tls.Config{NextProtos: []string{"h2", "http/1.1"}} Defensive patterns
Strategy: validation
Validate before calling
// Decide intentionally whether you want ALPN, then set NextProtos accordingly.
// If the server returns ALPN when you offered none, the fix is either to offer ALPN
// or to make the server stop sending it.
func wantsALPN(yes bool, cfg *tls.Config) {
if yes { cfg.NextProtos = []string{"h2", "http/1.1"} } else { cfg.NextProtos = nil }
} Type guard
func isUnrequestedALPN(err error) bool {
return err != nil && strings.Contains(err.Error(), "server advertised unrequested ALPN extension")
} Try / catch
if _, err := tls.Dial("tcp", addr, cfg); err != nil {
if isUnrequestedALPN(err) {
// Server bug; either accept ALPN by advertising it or report the defect.
cfg.NextProtos = []string{"http/1.1"}
_, err = tls.Dial("tcp", addr, cfg)
}
} Prevention
- Set Config.NextProtos when you expect ALPN.
- Report servers that send ALPN unsolicited.
When it happens
Trigger: Server sending an ALPN selection while the client offered no ALPN; middlebox injecting ALPN; buggy server with an unconditional ALPN response.
Common situations: Server with aggressive ALPN defaults; intermediary that adds ALPN; rare.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- tls: server did not select an ALPN protocol
- tls: server selected unadvertised ALPN protocol
- tls: invalid NextProtos value
- tls: NextProtos values too large
- tls: server echoed TLS 1.3 compatibility session ID in TLS 1
AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12).
Data as JSON: /api/errors/2180faf95362a078.
Report an issue: GitHub.