{"record":{"id":"8ba09d6c5574d1e8","repo":"thanos-io/thanos","slug":"no-tsdb-statistics","errorCode":null,"errorMessage":"no tsdb statistics","messagePattern":"no tsdb statistics","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/status/status.go","lineNumber":88,"sourceCode":"\tstatuspb.Status_TSDBStatisticsServer\n\tctx context.Context\n\n\tmtx            sync.Mutex\n\twarnings       annotations.Annotations\n\ttsdbStatistics map[string][]*statuspb.TSDBStatisticsEntry\n}\n\nfunc (srv *tsdbStatisticsServer) Send(res *statuspb.TSDBStatisticsResponse) error {\n\tif res.GetWarning() != \"\" {\n\t\tsrv.mtx.Lock()\n\t\tdefer srv.mtx.Unlock()\n\t\tsrv.warnings.Add(errors.New(res.GetWarning()))\n\t\treturn nil\n\t}\n\n\tstats := res.GetStatistics()\n\tif stats == nil {\n\t\treturn errors.New(\"no tsdb statistics\")\n\t}\n\n\tsrv.mtx.Lock()\n\tdefer srv.mtx.Unlock()\n\tfor tenant, tenantStats := range stats.Statistics {\n\t\tif _, found := srv.tsdbStatistics[tenant]; !found {\n\t\t\tsrv.tsdbStatistics[tenant] = nil\n\t\t}\n\t\tsrv.tsdbStatistics[tenant] = append(srv.tsdbStatistics[tenant], tenantStats)\n\t}\n\n\treturn nil\n}\n\nfunc (srv *tsdbStatisticsServer) Context() context.Context {\n\treturn srv.ctx\n}\n","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/thanos-io/thanos/blob/35b8b991177def87ed52dcf10f9b6d87f07282c8/pkg/status/status.go#L70-L106","documentation":"The gRPC streaming handler Send() in pkg/status/status.go:78 processes a TSDBStatisticsResponse and requires a non-nil Statistics payload. If a response arrives with neither a warning string nor a Statistics map, the server aborts the stream with 'no tsdb statistics'. This guards the aggregation logic that merges per-tenant TSDB stats from receiving an empty protobuf message.","triggerScenarios":"Calling Status.TSDBStatistics when the remote side returns a TSDBStatisticsResponse that has an empty Warning field and a nil Statistics field — i.e. a zero-value or partially populated response message from the peer.","commonSituations":"Version skew between Thanos components where an older peer does not populate Statistics; a gRPC server implementation (mock, proxy, or third-party) that returns an empty response; proto serialization where the Statistics oneof/field was dropped by an intermediary.","solutions":["Upgrade all Thanos components so peers send a populated TSDBStatisticsResponse (or a Warning instead of an empty message)","Check the responding component's implementation/mock: it must set either Warning or Statistics before calling Send","Capture gRPC client/server logs to identify which peer produced the empty response","If the error is transient for one unreachable store, treat it as a warning for that store and continue streaming from others"],"exampleFix":"// before (peer handler)\nres := &statuspb.TSDBStatisticsResponse{}\nif err := stream.Send(res); err != nil { return err }\n// after\nres := &statuspb.TSDBStatisticsResponse{Statistics: stats}\nif len(stats.Statistics) == 0 {\n    res = &statuspb.TSDBStatisticsResponse{Warning: \"no statistics available\"}\n}\nif err := stream.Send(res); err != nil { return err }","handlingStrategy":"type-guard","validationCode":"if res.GetWarning() == \"\" && res.GetStatistics() == nil {\n    return fmt.Errorf(\"peer %s returned empty TSDB statistics response\", peerAddr)\n}","typeGuard":"func hasStatistics(res *statuspb.TSDBStatisticsResponse) bool {\n    return res.GetWarning() != \"\" || res.GetStatistics() != nil\n}","tryCatchPattern":"if err := srv.Send(res); err != nil {\n    if err.Error() == \"no tsdb statistics\" {\n        logger.Warn(\"skipping peer with empty statistics response\", \"peer\", peerAddr)\n        return nil\n    }\n    return err\n}","preventionTips":["Always populate either Warning or Statistics before sending a TSDBStatisticsResponse","Run integration tests across all supported component versions","Add a peer-side guard that rejects building empty responses","Log peer identity on stream errors to ease triage"],"tags":["grpc","streaming","tsdb","thanos","status-api"],"backgroundTag":"empty-api-response","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"}