# Go "x509: certificate is valid for X, not Y": how to fix

> Go's crypto/x509 says the certificate's SANs do not include the host you dialed. Fix the name, ServerName or default certificate instead.

Source: https://ssl.sh/errors/go-x509-certificate-is-valid-for-not/
Last updated: 2026-11-10

**`x509: certificate is valid for www.example.com, not example.com` means the server's certificate covers the names before "not", and the host you connected to, after "not", is not one of them.** Connect with one of the listed names, send the right ServerName, or get a certificate that includes your host. `InsecureSkipVerify` is not a fix.

## What the error means

The host you dialed is missing from the certificate's Subject Alternative Names. When a Go TLS client verifies the server, it checks the host from the URL (or `tls.Config.ServerName`) against the certificate's Subject Alternative Names. On a mismatch, `crypto/x509` returns a `HostnameError`, and since Go 1.20 the TLS layer wraps it in a `CertificateVerificationError`. With `net/http` the full line looks like:

```text
Get "https://example.com/": tls: failed to verify certificate: x509: certificate is valid for www.example.com, not example.com
```

The `HostnameError` text varies with the situation, straight from Go's `verify.go`:

- `x509: certificate is valid for A, B, not C`: DNS SANs exist but none matches.
- `x509: certificate is valid for 203.0.113.5, not 203.0.113.10`: you dialed an IP and the IP SANs differ.
- `x509: cannot validate certificate for 203.0.113.10 because it doesn't contain any IP SANs`: you dialed an IP; the certificate has no IP SANs.
- `x509: certificate is not valid for any names, but wanted to match example.com`: no SANs at all.
- `x509: certificate relies on legacy Common Name field, use SANs instead`: the name is only in the CN; see [legacy Common Name](https://ssl.sh/errors/go-x509-certificate-relies-on-legacy-common-name/).

On Linux, where Go verifies certificates itself, the host name is checked before the chain is built. A self-signed default certificate from a proxy or ingress therefore often surfaces as this name error rather than as [signed by unknown authority](https://ssl.sh/errors/x509-certificate-signed-by-unknown-authority/).

## Causes, most common first

A URL with a name the certificate does not cover is the most common cause.

### 1. The URL uses a name the certificate does not cover

Bare domain versus `www`, an old alias, or a wildcard used too deep (`*.example.com` matches `api.example.com`, not `example.com` or `v1.api.example.com`).

- **Confirm:**

```bash
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -ext subjectAltName
```

- **Fix:** use a listed name, or reissue the certificate with every name you serve.

### 2. A proxy or ingress returns its default certificate

ingress-nginx serves a self-signed fallback certificate for `ingress.local` when no TLS secret matches; other load balancers and CDNs return their own default certificate for unknown hosts. The error then reads `valid for ingress.local, not example.com` or names the provider's domain.

- **Confirm:** `kubectl get ingress -A -o wide` and check that the Ingress has a `tls` entry with your host and an existing secret.
- **Fix:** add the TLS section and secret, or upload the certificate to the provider.

### 3. Dialing an IP or a different host without ServerName

Custom dialers, service discovery returning IPs, or `http.Transport` configured to connect to a fixed address all verify against whatever host Go thinks it is talking to. Without `ServerName`, Go sends no SNI for an IP, so a multi-site server may return the wrong certificate too.

- **Fix:** set `ServerName` (code below), or call the service by a DNS name that is on the certificate.

### 4. Internal services with incomplete SANs

Private CAs often issue certificates for `api.internal` while clients call `api.internal.example.com`, a Kubernetes service name or a Docker container name. Issue the certificate with every name and IP clients use.

### 5. A different server answered

If the names in the error belong to an unrelated site, DNS, `/etc/hosts`, a captive portal or a filtering proxy sent you elsewhere. Check `nslookup example.com` and compare with where the service should live.

## Fix commands by platform

Every fix makes the name the client verifies match a SAN in the certificate.

**Any OS, test a specific IP with the correct name (SNI and verification):**

```bash
curl -v --resolve example.com:443:203.0.113.10 https://example.com/
```

**Go, dial an IP but verify the real host name:**

```go
tr := &http.Transport{
    TLSClientConfig: &tls.Config{ServerName: "api.example.com"},
}
client := &http.Client{Transport: tr}
resp, err := client.Get("https://203.0.113.10/health")
```

**Kubernetes ingress-nginx:**

```yaml
spec:
  tls:
    - hosts: ["example.com", "www.example.com"]
      secretName: example-com-tls
  rules:
    - host: example.com
```

**Windows:** Go on Windows uses the platform verifier for chains, but the name rules are the same; check the certificate with `certutil -dump cert.cer` or the [certificate decoder](https://ssl.sh/tools/certificate-decoder/).

## Don't disable certificate verification

`tls.Config{InsecureSkipVerify: true}` makes Go accept any certificate and any host name. The Go documentation states that in this mode TLS is susceptible to machine-in-the-middle attacks unless custom verification is used, and that it should be used only for testing or together with `VerifyConnection` or `VerifyPeerCertificate`. In production that means anyone on the path can impersonate your API or registry and read credentials.

Safer alternatives: correct the host name, set `ServerName`, fix the ingress or CDN certificate, issue certificates with complete SANs, and for private CAs add the root to `RootCAs` or the system pool (`SSL_CERT_FILE` / `SSL_CERT_DIR` are honoured on Unix).

## Verify the fix

```go
conn, err := tls.Dial("tcp", "example.com:443", &tls.Config{})
if err != nil { log.Fatal(err) }
fmt.Println(conn.ConnectionState().PeerCertificates[0].DNSNames)
conn.Close()
```

The dial must succeed without error and print a list that includes the host you use. Check the public view with the [SSL checker](https://ssl.sh/tools/ssl-checker/), and read about [Subject Alternative Names](https://ssl.sh/glossary/san/) when planning a certificate's name list.
