thanos-io/thanos · error

could not get commonName field from client cert

Error message

could not get commonName field from client cert

What it means

Thrown by getTenantFromCertificate when the Common Name (CN) is configured as the tenant source but the presented client certificate has an empty Subject.CommonName. The proxy cannot identify the tenant and rejects the request.

Solutions

  1. Reissue the client certificate with a CN set to the tenant name (-subj '/CN=my-tenant')
  2. Or configure the server to use a populated field: --tenant-certificate-field=organization or organizationalUnit
  3. For cert-manager, add spec.commonName to the Certificate resource
  4. Verify with 'openssl x509 -noout -subject' that CN is present

Example fix

// before (cert-manager)
spec: {}
// after
spec:
  commonName: my-tenant
Defensive patterns

Strategy: validation

Validate before calling

// Go, check issued cert
if cert.Subject.CommonName == "" {
    return errors.New("client cert must have CommonName set for tenancy")
}

Type guard

func certHasCommonName(cert *x509.Certificate) bool {
    return cert != nil && cert.Subject.CommonName != ""
}

Prevention

When it happens

Trigger: GetTenantFromHTTP with certTenantField=CertificateFieldCommonName on a client cert whose Subject.CommonName is empty (modern CAs and tools increasingly omit CN by default).

Common situations: cert-manager Certificate resources without a commonName set (CN became optional in newer cert-manager); openssl req issued without a CN in -subj; server flag set to common-name while certs follow a SAN-only issuance policy.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07). Data as JSON: /api/errors/421b541ffc127e41. Report an issue: GitHub.

Appendix: source

Thrown at pkg/tenancy/tenancy.go:124

	cert := r.TLS.PeerCertificates[0]

	switch certTenantField {

	case CertificateFieldOrganization:
		if len(cert.Subject.Organization) == 0 {
			return "", errors.New("could not get organization field from client cert")
		}
		tenant = cert.Subject.Organization[0]

	case CertificateFieldOrganizationalUnit:
		if len(cert.Subject.OrganizationalUnit) == 0 {
			return "", errors.New("could not get organizationalUnit field from client cert")
		}
		tenant = cert.Subject.OrganizationalUnit[0]

	case CertificateFieldCommonName:
		if cert.Subject.CommonName == "" {
			return "", errors.New("could not get commonName field from client cert")
		}
		tenant = cert.Subject.CommonName

	default:
		return "", errors.New("tls client cert field requested is not supported")
	}

	return tenant, nil
}

func GetTenantFromGRPCMetadata(ctx context.Context) (string, bool) {
	md, ok := metadata.FromIncomingContext(ctx)
	if !ok || len(md.Get(DefaultTenantHeader)) == 0 {
		return DefaultTenant, false
	}
	return md.Get(DefaultTenantHeader)[0], true
}

View on GitHub (pinned to 35b8b99117)