golang/go · error

tls: invalid NextProtos value

Error message

tls: invalid NextProtos value

What it means

Thrown by makeClientHello when any entry in config.NextProtos (the ALPN protocol ID list) has a length of 0 or exceeds 255 bytes. ALPN protocol IDs are encoded with a single-byte length prefix on the wire, so each must be between 1 and 255 bytes long. An empty string or an excessively long protocol name violates this constraint.

Source

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

	serverHello  *serverHelloMsg
	hello        *clientHelloMsg
	suite        *cipherSuite
	finishedHash finishedHash
	masterSecret []byte
	session      *SessionState // the session being resumed
	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{

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Remove empty strings from config.NextProtos before use
  2. Ensure each ALPN protocol ID is between 1 and 255 bytes long
  3. Filter the NextProtos list programmatically: slices.DeleteFunc(nextProtos, func(s string) bool { return len(s) == 0 || len(s) > 255 })
  4. Validate ALPN entries from external input (config files, user input) before assigning to NextProtos

Example fix

// before
config := &tls.Config{
    NextProtos: []string{"h2", "", "http/1.1"}, // empty string → error
}
// after
config := &tls.Config{
    NextProtos: []string{"h2", "http/1.1"},
}
Defensive patterns

Strategy: validation

Validate before calling

func validateNextProtos(protos []string) error {
    for _, p := range protos {
        if l := len(p); l == 0 || l > 255 {
            return fmt.Errorf("invalid ALPN protocol length %d: must be 1-255 bytes", l)
        }
    }
    return nil
}

// Usage:
//   if err := validateNextProtos(config.NextProtos); err != nil {
//       log.Fatal(err)
//   }

Try / catch

// Pre-validate before assigning to config:
//
//   protos := slices.DeleteFunc(rawProtos, func(s string) bool {
//       return len(s) == 0 || len(s) > 255
//   })
//   config.NextProtos = protos

Prevention

When it happens

Trigger: Setting config.NextProtos to a slice containing an empty string (e.g., []string{"h2", ""}) or a string longer than 255 bytes (e.g., []string{strings.Repeat("a", 300)}).

Common situations: Accidentally including an empty string from a comma-split or whitespace-trim operation. Programmatically generated protocol names that exceed 255 bytes. A configuration file with a trailing comma producing an empty entry. Accidental nil interface conversion producing an empty string.

Understand the failure class

Related errors


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