thanos-io/thanos · error

no group

Error message

no group

What it means

rulesServer.Send returns 'no group' when a RulesResponse contains neither a Warning nor a Group. The rules proxy contract requires every streamed response to carry one of the two, so an empty response indicates a protocol violation by the sender.

Solutions

  1. Fix the sender to always populate either Group or Warning on every response
  2. Check for version mismatch between the ruler sending responses and the rules proxy
  3. Add a test asserting every streamed RulesResponse is non-empty
Defensive patterns

Strategy: validation

Validate before calling

if res.GetWarning() == "" && res.GetGroup() == nil {
    return errors.New("response must carry a group or a warning")
}

Type guard

func isUsableRulesResponse(res *rulespb.RulesResponse) bool {
    return res.GetWarning() != "" || res.GetGroup() != nil
}

Try / catch

if err != nil && strings.Contains(err.Error(), "no group") {
    log.Printf("sender emitted an empty RulesResponse: %v", err)
}

Prevention

When it happens

Trigger: An upstream/component streams a rulespb.RulesResponse with both Warning and Group unset — typically a misconfigured or buggy ruler, or a hand-constructed response in tests/custom code.

Common situations: Custom ruler implementations that emit empty responses; version skew where an old sender omits fields; faulty middleware mutating the response in transit.

Related errors


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

Appendix: source

Thrown at pkg/rules/rules.go:285

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

	warnings annotations.Annotations
	groups   []*rulespb.RuleGroup
	mu       sync.Mutex
}

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

	if res.GetGroup() == nil {
		return errors.New("no group")
	}

	srv.mu.Lock()
	defer srv.mu.Unlock()
	srv.groups = append(srv.groups, res.GetGroup())
	return nil
}

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

View on GitHub (pinned to 35b8b99117)