golang/go · error

tls: either ServerName or InsecureSkipVerify must be specifi

Error message

tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config

What it means

Thrown by makeClientHello when the tls.Config has an empty ServerName field and InsecureSkipVerify is false. The TLS client requires either a server hostname (for SNI extension and certificate hostname validation) or an explicit opt-in to skip certificate verification. This is a mandatory configuration check that prevents accidental insecure connections.

Source

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

	"time"
)

type clientHandshakeState struct {
	c            *Conn
	ctx          context.Context
	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")
	}

View on GitHub (pinned to b6b368adc5)

Solutions

  1. Set config.ServerName to the hostname you are connecting to (e.g., "example.com")
  2. Use tls.Dial instead of tls.Client — tls.Dial auto-sets ServerName from the host portion of the address
  3. If connecting by IP, set ServerName to the IP string literal so certificate validation can proceed
  4. Only in development/testing, set InsecureSkipVerify=true (never use in production — it disables all certificate verification)

Example fix

// before
config := &tls.Config{}
conn, err := tls.Dial("tcp", "example.com:443", config)
// ServerName is empty, InsecureSkipVerify is false → error

// after — tls.Dial auto-sets ServerName from host
conn, err := tls.Dial("tcp", "example.com:443", nil)
// or set explicitly:
config := &tls.Config{ServerName: "example.com"}
conn, err := tls.Dial("tcp", "example.com:443", config)
Defensive patterns

Strategy: validation

Validate before calling

func validateClientTLSConfig(config *tls.Config) error {
    if len(config.ServerName) == 0 && !config.InsecureSkipVerify {
        return errors.New("tls.Config must set ServerName or InsecureSkipVerify")
    }
    return nil
}

// Usage:
//   if err := validateClientTLSConfig(config); err != nil {
//       log.Fatal(err)
//   }
//   conn, err := tls.Dial("tcp", addr, config)

Type guard

// Type guard to check if a Config is safe for client use
func hasValidClientIdentity(config *tls.Config) bool {
    return len(config.ServerName) > 0 || config.InsecureSkipVerify
}

Try / catch

// Prefer pre-dial validation over try-catch:
//
//   if !hasValidClientIdentity(config) {
//       config.ServerName = hostnameFromAddress(addr)
//   }
//   conn, err := tls.Dial("tcp", addr, config)
//   if err != nil {
//       // handle connection error
//   }

Prevention

When it happens

Trigger: Calling tls.Dial, tls.DialWithDialer, or tls.Client with a tls.Config where ServerName is an empty string (or unset) and InsecureSkipVerify is false (the default).

Common situations: Creating a custom tls.Config with &tls.Config{} and forgetting to set ServerName. Dialing by IP address without setting ServerName to the IP string. Copying a Config struct and clearing ServerName. Using tls.Client directly (which does not auto-populate ServerName from the address, unlike tls.Dial).

Understand the failure class

Related errors


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