golang/go · error

tls: NextProtos values too large

Error message

tls: NextProtos values too large

What it means

Thrown by makeClientHello when the total serialized size of all config.NextProtos entries (including 1-byte length prefix per entry) exceeds 65535 bytes (0xFFFF). The ALPN extension encodes the protocol list with a uint16 overall length prefix, capping the total at 64KB. This is unlikely with normal usage but possible with many or very large protocol IDs.

Source

Thrown at src/crypto/tls/handshake_client.go:59

	ticket       []byte        // a fresh ticket received during this handshake
}

func (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echClientContext, error) {
	config := c.config
	if len(config.ServerName) == 0 && !config.InsecureSkipVerify {
		return nil, nil, nil, errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config")
	}

	nextProtosLength := 0
	for _, proto := range config.NextProtos {
		if l := len(proto); l == 0 || l > 255 {
			return nil, nil, nil, errors.New("tls: invalid NextProtos value")
		} else {
			nextProtosLength += 1 + l
		}
	}
	if nextProtosLength > 0xffff {
		return nil, nil, nil, errors.New("tls: NextProtos values too large")
	}

	supportedVersions := config.supportedVersions(roleClient, c.quic != nil)
	if len(supportedVersions) == 0 {
		return nil, nil, nil, errors.New("tls: no supported versions satisfy MinVersion and MaxVersion")
	}
	// Since supportedVersions is sorted in descending order, the first element
	// is the maximum version and the last element is the minimum version.
	maxVersion := supportedVersions[0]
	minVersion := supportedVersions[len(supportedVersions)-1]

	hello := &clientHelloMsg{
		vers:                         maxVersion,
		compressionMethods:           []uint8{compressionNone},
		random:                       make([]byte, 32),
		extendedMasterSecret:         true,
		ocspStapling:                 true,
		scts:                         true,

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Reduce the number of entries or the length of individual entries in config.NextProtos
  2. Remove unnecessary or duplicate ALPN protocol IDs — typically only 2-3 are needed (e.g., "h2", "http/1.1")
  3. Validate total size before assignment: ensure sum of (1 + len(proto)) for all entries is at most 65535
  4. Cap external input that feeds into NextProtos to a reasonable maximum

Example fix

// before — overly large protocol list
config := &tls.Config{
    NextProtos: generateLargeProtocolList(), // total > 64KB
}
// after — trim to essential protocols
config := &tls.Config{
    NextProtos: []string{"h2", "http/1.1"},
}
Defensive patterns

Strategy: validation

Validate before calling

func validateNextProtosSize(protos []string) error {
    total := 0
    for _, p := range protos {
        total += 1 + len(p)
    }
    if total > 0xffff {
        return fmt.Errorf("total NextProtos size %d exceeds 65535 bytes", total)
    }
    return nil
}

Try / catch

// Pre-validate total size:
//
//   if err := validateNextProtosSize(config.NextProtos); err != nil {
//       config.NextProtos = config.NextProtos[:2] // trim to essential protocols
//   }

Prevention

When it happens

Trigger: Setting config.NextProtos to a slice where the sum of (1 + len(proto)) for all entries exceeds 0xFFFF (65535).

Common situations: Accidentally duplicating entries many times in a loop. Including extremely long protocol ID strings. A programming error that appends a large data structure as protocol names. Generating NextProtos from unbounded external input without size limits.

Understand the failure class

Related errors


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