thanos-io/thanos · error

could not get organizationalUnit field from client cert

Error message

could not get organizationalUnit field from client cert

What it means

Thrown by getTenantFromCertificate when tenancy is configured to use the certificate's OrganizationalUnit (OU) field as the tenant identifier, but the client certificate presented has no OrganizationalUnit entries. Tenancy cannot be determined so the request fails.

Solutions

  1. Add an OrganizationalUnit to the client cert Subject and reissue it (e.g. -subj '/O=corp/OU=tenant-a/CN=client')
  2. Or change the server flag to a field present in the cert: --tenant-certificate-field=organization or common-name
  3. Inspect the client cert subject with 'openssl x509 -noout -subject' to see available fields
  4. Document the required cert subject layout so all tenants issue compliant certs

Example fix

// before
-subj '/CN=client'
// after
-subj '/OU=tenant-a/CN=client'
Defensive patterns

Strategy: validation

Validate before calling

// Go, before issuing/connecting
if len(cert.Subject.OrganizationalUnit) == 0 {
    return errors.New("client cert must have OrganizationalUnit set for tenancy")
}

Type guard

func certHasOU(cert *x509.Certificate) bool {
    return cert != nil && len(cert.Subject.OrganizationalUnit) > 0
}

Prevention

When it happens

Trigger: GetTenantFromHTTP with certTenantField=CertificateFieldOrganizationalUnit against a client cert whose Subject.OrganizationalUnit slice is empty.

Common situations: Server started with --tenant-certificate-field=organizationalUnit but clients use certs with only CN/O populated; certs rotated to a new CA template that dropped the OU field; misconfiguration of the tenant field flag in multi-tenant deployments.

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/e38b4a266bbb6ed7. Report an issue: GitHub.

Appendix: source

Thrown at pkg/tenancy/tenancy.go:118

	if len(r.TLS.PeerCertificates) == 0 {
		return "", errors.New("could not get required certificate field from client cert")
	}

	// First cert is the leaf authenticated against.
	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)

View on GitHub (pinned to 35b8b99117)