thanos-io/thanos · error · ApiError

retrieving metadata

Error message

retrieving metadata

What it means

Wraps any failure from the store client's MetricMetadata gRPC call during /api/v1/metadata handling. It is classified as an internal error (ErrorInternal), meaning the query-side plumbing failed rather than the request being bad.

Solutions

  1. Check querier-to-store connectivity and that store gateways are healthy (`thanos tools bucket verify`, store /-/healthy).
  2. Inspect querier logs for the wrapped root cause; retry the request.
  3. Verify store gRPC services are registered and the Querier's store address set includes reachable endpoints.
Defensive patterns

Strategy: retry

Try / catch

const resp = await fetch(`${base}/api/v1/metadata?limit=100`);
if (!resp.ok) {
  const body = await resp.json();
  if (body.errorType === 'internal') {
    // check store health, then retry with backoff
    await sleep(backoff);
    return retry();
  }
  throw new Error(body.error);
}

Prevention

When it happens

Trigger: The store/storeAPI backing the querier returns an error or the RPC fails while fetching metric metadata (network drop, store unavailable, store-side limit/parse errors).

Common situations: Store gateway down or restarting, network partitions between querier and store, timeouts on large metadata sets, store nodes returning gRPC errors.

Related errors


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

Appendix: source

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

			Limit:                   -1,
			Metric:                  r.URL.Query().Get("metric"),
			PartialResponseStrategy: ps,
		}

		limitStr := r.URL.Query().Get("limit")
		if limitStr != "" {
			limit, err := strconv.ParseInt(limitStr, 10, 32)
			if err != nil {
				return nil, nil, &api.ApiError{Typ: api.ErrorBadData, Err: errors.Errorf("invalid metric metadata limit='%v'", limit)}, func() {}
			}
			req.Limit = int32(limit)
		}

		tracing.DoInSpan(ctx, "retrieve_metadata", func(ctx context.Context) {
			t, warnings, err = client.MetricMetadata(ctx, req)
		})
		if err != nil {
			return nil, nil, &api.ApiError{Typ: api.ErrorInternal, Err: errors.Wrap(err, "retrieving metadata")}, func() {}
		}

		return t, warnings.AsErrors(), nil, func() {}
	}
}

func (qapi *QueryAPI) tsdbStatus(r *http.Request) (any, []error, *api.ApiError, func()) {
	span, ctx := tracing.StartSpan(r.Context(), "tsdb_statistics_query_request")
	defer span.Finish()

	if err := r.ParseForm(); err != nil {
		return nil, nil, &api.ApiError{Typ: api.ErrorInternal, Err: errors.Wrap(err, "parse form")}, func() {}
	}

	ps := storepb.PartialResponseStrategy_ABORT
	if qapi.enableStatusPartialResponse {
		ps = storepb.PartialResponseStrategy_WARN
	}

View on GitHub (pinned to 35b8b99117)