hashicorp/nomad · error

invalid certificate: %s not in expected %s

Error message

invalid certificate: %s not in expected %s

What it means

validateCertificateForNames checks that the TLS certificate presented by the peer contains at least one of the names the verifier expects. If none of the certificate's valid names (SANs/CNs) intersect the expected names, it fails with 'invalid certificate: <cert names> not in expected <expected names>'. This is mTLS name verification rejecting a certificate issued for different identities.

Source

Thrown at nomad/auth/auth.go:443

}

// validateCertificateForNames returns true if the certificate is valid for any
// of the given domain names.
func validateCertificateForNames(cert *x509.Certificate, expectedNames []string) (bool, error) {
	if cert == nil {
		return false, nil
	}

	validNames := []string{cert.Subject.CommonName}
	validNames = append(validNames, cert.DNSNames...)

	for _, expectedName := range expectedNames {
		if slices.Contains(validNames, expectedName) {
			return true, nil
		}
	}

	return false, fmt.Errorf("invalid certificate: %s not in expected %s",
		strings.Join(validNames, ", "),
		strings.Join(expectedNames, ", "))

}

// IdentityToACLClaim returns an ACLClaim suitable for checking permissions
func IdentityToACLClaim(ai *structs.AuthenticatedIdentity, store *state.StateStore) *acl.ACLClaim {
	if ai == nil || ai.Claims == nil {
		return nil
	}

	var group string
	alloc, err := store.AllocByID(nil, ai.Claims.AllocationID)
	if err != nil {
		// we should never hit this error, but if we did the caller would get a
		// nil claim and auth will fail
		return nil
	}

View on GitHub (pinned to 482b49bf1a)

Solutions

  1. Reissue the certificate with SANs/CNs covering the expected names shown in the error message
  2. Fix the PKI/CA role template so issued certs include the required Nomad service names (e.g. server.<region>.nomad, client.<region>.nomad)
  3. Ensure the correct certificate (server vs client) is configured for the given connection direction
  4. If the expected names changed (region rename, host change), reissue certs or update the expected-name configuration

Example fix

// before: cert issued without expected SAN
// openssl req ... -addext 'subjectAltName=DNS:localhost' // insufficient
// after: include expected Nomad names
// openssl req ... -addext 'subjectAltName=DNS:server.region1.nomad,DNS:client.global.nomad'
Defensive patterns

Strategy: validation

Validate before calling

cert, err := tls.X509KeyPair(certPEM, keyPEM)
x509Cert, _ := x509.ParseCertificate(cert.Certificate[0])
expected := []string{"server.region1.nomad", "client.region1.nomad"}
for _, name := range x509Cert.DNSNames {
    if slices.Contains(expected, name) { return nil }
}
return errors.New("cert SANs do not include expected Nomad names")

Type guard

func certCoversExpectedNames(cert *x509.Certificate, expected []string) bool {
    names := append(cert.DNSNames, cert.Subject.CommonName)
    for _, e := range expected {
        if slices.Contains(names, e) { return true }
    }
    return false
}

Try / catch

if err != nil && strings.Contains(err.Error(), "invalid certificate:") {
    // parse the 'not in expected' list from the message and reissue the cert
    return fmt.Errorf("reissue certificate with required SANs: %w", err)
}

Prevention

When it happens

Trigger: A TLS (mTLS) handshake/verification where the peer's certificate SAN/CN list does not include any of the expected service names — e.g. checking a cert whose names are 'client.region1.nomad' against expected 'server.region1.nomad'.

Common situations: Certificate generated without the required SANs; using a client cert where a server cert is expected; region/hostname changed after cert issuance; CA template (e.g. Vault PKI) misconfigured with wrong role names.

Understand the failure class

Related errors


AI-assisted analysis of hashicorp/nomad@482b49bf1a (2026-09-04). Data as JSON: /api/errors/3e1ee75d9790ec1a. Report an issue: GitHub.