golang/go · error

tls: client offered TLS version older than TLS 1.3

Error message

tls: client offered TLS version older than TLS 1.3

What it means

RFC 9001 §4.2 mandates QUIC use TLS 1.3 minimum; older TLS versions are forbidden in QUIC. If any entry in the QUIC ClientHello's supportedVersions is below VersionTLS13 (0x0304), the server sends protocol_version and aborts.

Source

Thrown at src/crypto/tls/handshake_server_tls13.go:272

	hs.sharedKey, hs.hello.serverShare, err = ke.serverSharedSecret(c.config.rand(), clientKeyShare.data)
	if err != nil {
		c.sendAlert(alertIllegalParameter)
		return errors.New("tls: invalid client key share")
	}

	selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols, c.quic != nil)
	if err != nil {
		c.sendAlert(alertNoApplicationProtocol)
		return err
	}
	c.clientProtocol = selectedProto

	if c.quic != nil {
		// RFC 9001 Section 4.2: Clients MUST NOT offer TLS versions older than 1.3.
		for _, v := range hs.clientHello.supportedVersions {
			if v < VersionTLS13 {
				c.sendAlert(alertProtocolVersion)
				return errors.New("tls: client offered TLS version older than TLS 1.3")
			}
		}
		// RFC 9001 Section 8.2.
		if hs.clientHello.quicTransportParameters == nil {
			c.sendAlert(alertMissingExtension)
			return errors.New("tls: client did not send a quic_transport_parameters extension")
		}
		c.quicSetTransportParameters(hs.clientHello.quicTransportParameters)
	} else {
		if hs.clientHello.quicTransportParameters != nil {
			c.sendAlert(alertUnsupportedExtension)
			return errors.New("tls: client sent an unexpected quic_transport_parameters extension")
		}
	}

	c.serverName = hs.clientHello.serverName
	return nil
}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Configure the QUIC client to advertise only TLS 1.3 (0x0304) in supported_versions
  2. Use a QUIC stack that conforms to RFC 9001 (do not mix TLS 1.2 code paths with QUIC)

Example fix

// before
supportedVersions = []uint16{0x0303, 0x0304}

// after
supportedVersions = []uint16{0x0304}
Defensive patterns

Strategy: validation

Validate before calling

// QUIC client: ensure no TLS version below 1.3 is advertised.
for _, v := range supportedVersions {
    if v < 0x0304 {
        return fmt.Errorf("QUIC forbids TLS version 0x%04x", v)
    }
}

Try / catch

if err := tlsConn.Handshake(); err != nil {
    if strings.Contains(err.Error(), "older than TLS 1.3") {
        log.Printf("QUIC client advertised pre-1.3 from %v", remote)
    }
    c.Close()
    return
}

Prevention

When it happens

Trigger: A QUIC handshake where the client includes TLS 1.2 (0x0303) or earlier in supportedVersions.

Common situations: A QUIC stack that incorrectly advertises TLS 1.2 compatibility; a TLS 1.2 client mistakenly run over a QUIC transport; QUIC/TLS interop bugs.

Understand the failure class

Related errors


AI-assisted analysis of golang/go@b6b368adc5 (2026-08-12). Data as JSON: /api/errors/51e8a53fa22d941b. Report an issue: GitHub.