thanos-io/thanos · error
could not get required certificate field from client cert
Error message
could not get required certificate field from client cert
What it means
getTenantFromCertificate extracts the tenant ID from the client's mTLS certificate (OU or CN depending on configured field). If the TLS handshake produced no peer certificates (r.TLS.PeerCertificates empty), the tenant cannot be extracted and this error is returned.
Solutions
- Require client certificates: set tls.Config ClientAuth to tls.RequireAndVerifyClientCert and reconfigure the client to present its cert.
- If a proxy/LB terminates TLS, enable client-cert passthrough (PROXY protocol / header injection) or move tenant extraction to the proxy.
- Confirm the request is HTTPS; GetTenantFromHTTP only inspects r.TLS, which is nil for plain HTTP.
- If certs are not your tenant mechanism, switch Options.TenantField to the header-based option instead.
Example fix
// before
tlsConfig := &tls.Config{} // no client auth
// after
tlsConfig := &tls.Config{
ClientAuth: tls.RequireAndVerifyClientCert,
ClientCAs: caPool,
} Defensive patterns
Strategy: validation
Validate before calling
if r.TLS == nil || len(r.TLS.PeerCertificates) == 0 {
http.Error(w, "client certificate required", http.StatusUnauthorized)
return
} Type guard
func hasPeerCert(r *http.Request) bool { return r.TLS != nil && len(r.TLS.PeerCertificates) > 0 } Try / catch
tenant, err := tenancy.GetTenantFromHTTP(r, header, def, field)
if err != nil {
http.Error(w, err.Error(), http.StatusUnauthorized)
return
} Prevention
- Enforce tls.RequireAndVerifyClientCert server-side
- Only expose tenant extraction on HTTPS handlers
- Handle TLS termination at the proxy correctly (passthrough or header injection)
- Decide one tenant source (cert or header) and configure consistently
When it happens
Trigger: getTenantFromCertificate is called by GetTenantFromHTTP with certTenantField set to a certificate field, but the request was not authenticated with a client certificate — r.TLS is nil-capable or PeerCertificates has length 0 (e.g. request over plain HTTP or server not requesting client certs).
Common situations: Client connects without mTLS (plain HTTP or TLS without client auth); server's tls.Config ClientAuth set to NoClientCert/RequestClientCert and client sent no cert; a load balancer terminates TLS so the server never sees peer certs; TenantField option set to certificate while users authenticate via header.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- could not get organization field from client cert
- could not get organizationalUnit field from client cert
- could not get commonName field from client cert
- client credentials
- error getting tenant from HTTP
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/ddb4e347199c1385.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/tenancy/tenancy.go:102
return roundTripperFunc(func(r *http.Request) (*http.Response, error) {
tenant, _ := GetTenantFromHTTP(r, customTenantHeader, DefaultTenant, certTenantField)
r.Header.Set(DefaultTenantHeader, tenant)
// If the custom tenant header is not the same as the default internal header, we want to exclude the custom
// one from the request to keep things simple.
if customTenantHeader != DefaultTenantHeader {
r.Header.Del(customTenantHeader)
}
return next.RoundTrip(r)
})
}
// getTenantFromCertificate extracts the tenant value from a client's presented certificate. The x509 field to use as
// value can be configured with Options.TenantField. An error is returned when the extraction has not succeeded.
func getTenantFromCertificate(r *http.Request, certTenantField string) (string, error) {
var tenant string
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]View on GitHub (pinned to 35b8b99117)