{"record":{"id":"74806b5bbbdd8a97","repo":"thanos-io/thanos","slug":"no-group","errorCode":null,"errorMessage":"no group","messagePattern":"no group","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/rules/rules.go","lineNumber":285,"sourceCode":"\t// This field just exist to pseudo-implement the unused methods of the interface.\n\trulespb.Rules_RulesServer\n\tctx context.Context\n\n\twarnings annotations.Annotations\n\tgroups   []*rulespb.RuleGroup\n\tmu       sync.Mutex\n}\n\nfunc (srv *rulesServer) Send(res *rulespb.RulesResponse) error {\n\tif res.GetWarning() != \"\" {\n\t\tsrv.mu.Lock()\n\t\tdefer srv.mu.Unlock()\n\t\tsrv.warnings.Add(errors.New(res.GetWarning()))\n\t\treturn nil\n\t}\n\n\tif res.GetGroup() == nil {\n\t\treturn errors.New(\"no group\")\n\t}\n\n\tsrv.mu.Lock()\n\tdefer srv.mu.Unlock()\n\tsrv.groups = append(srv.groups, res.GetGroup())\n\treturn nil\n}\n\nfunc (srv *rulesServer) Context() context.Context {\n\treturn srv.ctx\n}\n","sourceCodeStart":267,"sourceCodeEnd":297,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/rules/rules.go#L267-L297","documentation":"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.","triggerScenarios":"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.","commonSituations":"Custom ruler implementations that emit empty responses; version skew where an old sender omits fields; faulty middleware mutating the response in transit.","solutions":["Fix the sender to always populate either Group or Warning on every response","Check for version mismatch between the ruler sending responses and the rules proxy","Add a test asserting every streamed RulesResponse is non-empty"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"if res.GetWarning() == \"\" && res.GetGroup() == nil {\n    return errors.New(\"response must carry a group or a warning\")\n}","typeGuard":"func isUsableRulesResponse(res *rulespb.RulesResponse) bool {\n    return res.GetWarning() != \"\" || res.GetGroup() != nil\n}","tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"no group\") {\n    log.Printf(\"sender emitted an empty RulesResponse: %v\", err)\n}","preventionTips":["Ensure every response written to the stream populates Group or Warning","Pin compatible versions of ruler and rules proxy","Add contract tests that stream at least one non-empty response"],"tags":["grpc","protocol","rules"],"backgroundTag":"unexpected-response-shape","analyzedSha":"35b8b991177def87ed52dcf10f9b6d87f07282c8","analyzedAt":"2026-09-07T01:49:59.689Z","contentChangedAt":"2026-09-07T01:49:59.689Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}