thanos-io/thanos · error
tenant name not valid
Error message
tenant name not valid
What it means
IsTenantValid validates a multi-tenancy tenant ID by ensuring it is a single path element (tenant == path.Base(tenant)). Tenant IDs are used in object storage paths, so values containing '/' or being '.' would break storage layout or escape directories.
Solutions
- Send the correct tenant header (e.g. THanos-Scope: <id>) with a simple identifier containing no '/' and not empty.
- Validate the tenant at configuration/startup: call tenancy.IsTenantValid(tenant) and fail fast with a clear message.
- If you need hierarchical tenants, encode the hierarchy without '/' (e.g. use '-' separator).
- Check reverse proxy/gateway config so it forwards the tenant header verbatim and doesn't inject request paths.
Example fix
// before
tenant := r.URL.Path // "org/team"
// after
tenant := r.Header.Get("THanos-Scope") // "org-team"
if err := tenancy.IsTenantValid(tenant); err != nil { http.Error(w, err.Error(), http.StatusBadRequest); return } Defensive patterns
Strategy: validation
Validate before calling
func tenantOK(t string) bool { return t != "" && t == path.Base(t) } Try / catch
if err := tenancy.IsTenantValid(tenant); err != nil {
http.Error(w, "invalid tenant", http.StatusBadRequest)
return
} Prevention
- Always require a tenant header with a simple identifier
- Fail fast at startup for configured tenants
- Encode hierarchy with '-' instead of '/'
- Test gateways forward the tenant header unchanged
When it happens
Trigger: IsTenantValid(tenant) returns this error when tenant != path.Base(tenant) — e.g. tenant contains '/', is empty (path.Base("") == "."), or equals ".".
Common situations: Missing tenant header causing empty string; a downstream proxy appending path-like IDs ("org/team") as tenants; URL parsing pulling tenant from a path segment including slashes; clients configured with wrong tenant header name.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- error getting tenant from HTTP
- unsupported format for label
- --auto-gomemlimit.ratio must be greater than 0 and less…
- unexpected downsampling resolution
- input block index not valid
AI-assisted analysis of thanos-io/thanos@35b8b99117 (2026-09-07).
Data as JSON: /api/errors/46df79044516f558.
Report an issue: GitHub.
Appendix: source
Thrown at pkg/tenancy/tenancy.go:43
DefaultTenant = "default-tenant"
// DefaultTenantLabel is the default label-name with which the tenant is announced in stored metrics.
DefaultTenantLabel = "tenant_id"
// This key is used to pass tenant information using Context.
TenantKey contextKey = 0
// MetricLabel is the label name used for adding tenant information to exported metrics.
MetricLabel = "tenant"
)
// Allowed fields in client certificates.
const (
CertificateFieldOrganization = "organization"
CertificateFieldOrganizationalUnit = "organizationalUnit"
CertificateFieldCommonName = "commonName"
)
func IsTenantValid(tenant string) error {
if tenant != path.Base(tenant) {
return errors.New("tenant name not valid")
}
return nil
}
// GetTenantFromHTTP extracts the tenant from a http.Request object.
func GetTenantFromHTTP(r *http.Request, tenantHeader string, defaultTenantID string, certTenantField string) (string, error) {
var err error
tenant := r.Header.Get(tenantHeader)
if tenant == "" {
tenant = r.Header.Get(DefaultTenantHeader)
if tenant == "" {
tenant = defaultTenantID
}
}
if certTenantField != "" {
tenant, err = getTenantFromCertificate(r, certTenantField)
if err != nil {View on GitHub (pinned to 35b8b99117)