thanos-io/thanos · error

no targets

Error message

no targets

What it means

This error is returned by the internal targetsServer.Send when a TargetsResponse arrives with neither a warning nor a Targets payload. The proxy expects every non-warning response to carry target sets; nil means the upstream violated the expected response shape.

Solutions

  1. Identify which upstream endpoint produced the nil response (enable gRPC/logging per-endpoint) and check its version/health.
  2. Upgrade or fix the offending TargetsAPI implementation so it returns Targets or a Warning, never neither.
  3. Check for protobuf version skew between querier and providers (regenerate/align targetspb types).
  4. As a caller, treat this endpoint as failing and exclude it from the store set.

Example fix

// before
resp, err := targetsClient.Targets(ctx, req)
// after: guard at call site
if resp != nil && resp.GetTargets() == nil && resp.GetWarning() == "" {
    return nil, errors.New("upstream returned neither targets nor warning")
}
Defensive patterns

Strategy: validation

Validate before calling

if res.GetWarning() == "" && res.GetTargets() == nil {
    return errors.New("upstream sent neither targets nor warning")
}

Type guard

func validTargetsResponse(res *targetspb.TargetsResponse) bool {
    return res.GetWarning() != "" || res.GetTargets() != nil
}

Prevention

When it happens

Trigger: Send() on targetsServer is called with a response where res.GetTargets() == nil and res.GetWarning() == "" — an upstream TargetsAPI returned a response with no targets and no warning.

Common situations: A non-Thanos or buggy gRPC server registered as a TargetsAPI endpoint returning empty/nil payloads; version skew where an older binary responds with a different message shape.

Related errors


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

Appendix: source

Thrown at pkg/targets/targets.go:202

	// This field just exist to pseudo-implement the unused methods of the interface.
	targetspb.Targets_TargetsServer
	ctx context.Context

	warnings annotations.Annotations
	targets  *targetspb.TargetDiscovery
	mu       sync.Mutex
}

func (srv *targetsServer) Send(res *targetspb.TargetsResponse) error {
	if res.GetWarning() != "" {
		srv.mu.Lock()
		defer srv.mu.Unlock()
		srv.warnings.Add(errors.New(res.GetWarning()))
		return nil
	}

	if res.GetTargets() == nil {
		return errors.New("no targets")
	}
	srv.mu.Lock()
	defer srv.mu.Unlock()
	srv.targets.ActiveTargets = append(srv.targets.ActiveTargets, res.GetTargets().ActiveTargets...)
	srv.targets.DroppedTargets = append(srv.targets.DroppedTargets, res.GetTargets().DroppedTargets...)

	return nil
}

func (srv *targetsServer) Context() context.Context {
	return srv.ctx
}

View on GitHub (pinned to 35b8b99117)