thanos-io/thanos · error · ApiError

tenant not found

Error message

%s tenant not found

What it means

When a `tenant` query param is provided, the response map from TSDBStatistics must contain an entry keyed by that tenant; if the map has no such key, this internal error (wrapped as '%s tenant not found') is returned.

Solutions

  1. Verify the tenant name matches exactly the tenant key reported in stats (case-sensitive).
  2. Drop the tenant param to get merged statistics from all tenants and inspect available tenant keys.
  3. Ensure the request reaches stores that actually hold the tenant's data (correct routing/sidecar/store-gateway config).

Example fix

// before
GET /api/v1/tsdb/status?tenant=mytenant  // store has "MyTenant"
// after
GET /api/v1/tsdb/status  // inspect available tenants, then use exact key
GET /api/v1/tsdb/status?tenant=MyTenant
Defensive patterns

Strategy: fallback

Try / catch

let data = await fetch(`${base}/api/v1/tsdb/status?tenant=${encodeURIComponent(tenant)}`).then(r => r.json());
if (data.status === 'error' && /tenant not found/.test(data.error)) {
  // fall back to merged stats to discover valid tenant keys
  data = await fetch(`${base}/api/v1/tsdb/status`).then(r => r.json());
}

Prevention

When it happens

Trigger: GET /api/v1/tsdb/status?tenant=foo where no store returned statistics for tenant 'foo' — the tenant does not exist, has an empty TSDB, or the request was served by stores that don't own that tenant's data.

Common situations: Typo in tenant name; querying against stores/route paths of a different tenant (multi-tenant setups); tenant with no data at query time; hitting a Thanos receive/querier that doesn't serve that tenant.

Understand the failure class

Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at pkg/api/query/v1.go:1767

	}
	req := &statuspb.TSDBStatisticsRequest{
		Matchers:                matchers,
		Limit:                   int32(limit),
		PartialResponseStrategy: ps,
	}

	var stats map[string]*statuspb.TSDBStatisticsEntry
	tracing.DoInSpan(ctx, "retrieve_tsdb_statistics", func(ctx context.Context) {
		stats, warnings, err = qapi.status.TSDBStatistics(ctx, req)
	})

	if err != nil {
		return nil, nil, &api.ApiError{Typ: api.ErrorInternal, Err: errors.Wrap(err, "retrieving tsdb statistics")}, func() {}
	}

	if tenant != "" {
		if stats[tenant] == nil {
			return nil, nil, &api.ApiError{Typ: api.ErrorInternal, Err: errors.Wrap(fmt.Errorf("%s tenant not found", tenant), "retrieving tsdb statistics")}, func() {}
		}

		return convertToTSDBSTatus(stats[tenant], limit), warnings.AsErrors(), nil, func() {}
	}

	// Merge statistics from all tenants.
	aggregatedStats := &statuspb.TSDBStatisticsEntry{}
	for _, v := range stats {
		aggregatedStats.Merge(v)
	}

	return convertToTSDBSTatus(aggregatedStats, limit), warnings.AsErrors(), nil, func() {}
}

func convertToTSDBSTatus(tsdbStatsEntry *statuspb.TSDBStatisticsEntry, limit int) *v1.TSDBStatus {
	return &v1.TSDBStatus{
		HeadStats: v1.HeadStats{
			NumSeries:     tsdbStatsEntry.HeadStatistics.NumSeries,

View on GitHub (pinned to 35b8b99117)