{"record":{"id":"bd6f4c72edad9125","repo":"golang/go","slug":"tls-either-servername-or-insecureskipverify-must","errorCode":null,"errorMessage":"tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config","messagePattern":"tls: either ServerName or InsecureSkipVerify must be specified in the tls\\.Config","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/crypto/tls/handshake_client.go","lineNumber":47,"sourceCode":"\t\"time\"\n)\n\ntype clientHandshakeState struct {\n\tc            *Conn\n\tctx          context.Context\n\tserverHello  *serverHelloMsg\n\thello        *clientHelloMsg\n\tsuite        *cipherSuite\n\tfinishedHash finishedHash\n\tmasterSecret []byte\n\tsession      *SessionState // the session being resumed\n\tticket       []byte        // a fresh ticket received during this handshake\n}\n\nfunc (c *Conn) makeClientHello() (*clientHelloMsg, *keySharePrivateKeys, *echClientContext, error) {\n\tconfig := c.config\n\tif len(config.ServerName) == 0 && !config.InsecureSkipVerify {\n\t\treturn nil, nil, nil, errors.New(\"tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config\")\n\t}\n\n\tnextProtosLength := 0\n\tfor _, proto := range config.NextProtos {\n\t\tif l := len(proto); l == 0 || l > 255 {\n\t\t\treturn nil, nil, nil, errors.New(\"tls: invalid NextProtos value\")\n\t\t} else {\n\t\t\tnextProtosLength += 1 + l\n\t\t}\n\t}\n\tif nextProtosLength > 0xffff {\n\t\treturn nil, nil, nil, errors.New(\"tls: NextProtos values too large\")\n\t}\n\n\tsupportedVersions := config.supportedVersions(roleClient, c.quic != nil)\n\tif len(supportedVersions) == 0 {\n\t\treturn nil, nil, nil, errors.New(\"tls: no supported versions satisfy MinVersion and MaxVersion\")\n\t}","sourceCodeStart":29,"sourceCodeEnd":65,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/tls/handshake_client.go#L29-L65","documentation":"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.","triggerScenarios":"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).","commonSituations":"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).","solutions":["Set config.ServerName to the hostname you are connecting to (e.g., \"example.com\")","Use tls.Dial instead of tls.Client — tls.Dial auto-sets ServerName from the host portion of the address","If connecting by IP, set ServerName to the IP string literal so certificate validation can proceed","Only in development/testing, set InsecureSkipVerify=true (never use in production — it disables all certificate verification)"],"exampleFix":"// before\nconfig := &tls.Config{}\nconn, err := tls.Dial(\"tcp\", \"example.com:443\", config)\n// ServerName is empty, InsecureSkipVerify is false → error\n\n// after — tls.Dial auto-sets ServerName from host\nconn, err := tls.Dial(\"tcp\", \"example.com:443\", nil)\n// or set explicitly:\nconfig := &tls.Config{ServerName: \"example.com\"}\nconn, err := tls.Dial(\"tcp\", \"example.com:443\", config)","handlingStrategy":"validation","validationCode":"func validateClientTLSConfig(config *tls.Config) error {\n    if len(config.ServerName) == 0 && !config.InsecureSkipVerify {\n        return errors.New(\"tls.Config must set ServerName or InsecureSkipVerify\")\n    }\n    return nil\n}\n\n// Usage:\n//   if err := validateClientTLSConfig(config); err != nil {\n//       log.Fatal(err)\n//   }\n//   conn, err := tls.Dial(\"tcp\", addr, config)","typeGuard":"// Type guard to check if a Config is safe for client use\nfunc hasValidClientIdentity(config *tls.Config) bool {\n    return len(config.ServerName) > 0 || config.InsecureSkipVerify\n}","tryCatchPattern":"// Prefer pre-dial validation over try-catch:\n//\n//   if !hasValidClientIdentity(config) {\n//       config.ServerName = hostnameFromAddress(addr)\n//   }\n//   conn, err := tls.Dial(\"tcp\", addr, config)\n//   if err != nil {\n//       // handle connection error\n//   }","preventionTips":["Always set ServerName in tls.Config for client connections","Use tls.Dial (not tls.Client) which auto-sets ServerName from the address host","Never use InsecureSkipVerify in production code","Write a Config builder/constructor that enforces ServerName as a required parameter"],"tags":["tls","client-side","config","sni","certificate-verification"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}