From 106e6f2c7771ab1f5fb7e7d200a04ab69a58683b Mon Sep 17 00:00:00 2001 From: Minh Nguyen <148210689+pipiland2612@users.noreply.github.com> Date: Mon, 6 Oct 2025 14:53:44 +0300 Subject: [PATCH] [RW2] Return 400 for Exemplars without Series or Histograms not written (#17250) * fix Signed-off-by: pipiland2612 * fix cmt Signed-off-by: pipiland2612 --------- Signed-off-by: pipiland2612 --- storage/remote/write_handler.go | 6 ++++++ storage/remote/write_handler_test.go | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/storage/remote/write_handler.go b/storage/remote/write_handler.go index dc058cc9b9..d134fc9403 100644 --- a/storage/remote/write_handler.go +++ b/storage/remote/write_handler.go @@ -429,6 +429,12 @@ func (h *writeHandler) appendV2(app storage.Appender, req *writev2.Request, rs * continue } + // Validate that the TimeSeries has at least one sample or histogram. + if len(ts.Samples) == 0 && len(ts.Histograms) == 0 { + badRequestErrs = append(badRequestErrs, fmt.Errorf("TimeSeries must contain at least one sample or histogram for series %v", ls.String())) + continue + } + allSamplesSoFar := rs.AllSamples() var ref storage.SeriesRef diff --git a/storage/remote/write_handler_test.go b/storage/remote/write_handler_test.go index d37e039937..4fb721ca13 100644 --- a/storage/remote/write_handler_test.go +++ b/storage/remote/write_handler_test.go @@ -418,6 +418,22 @@ func TestRemoteWriteHandler_V2Message(t *testing.T) { expectedCode: http.StatusBadRequest, expectedRespBody: "parsing labels for series [1 999]: labelRefs 1 (name) = 999 (value) outside of symbols table (size 18)\n", }, + { + desc: "Partial write; TimeSeries with only exemplars (no samples or histograms)", + input: append( + // Series with only exemplars, no samples or histograms. + []writev2.TimeSeries{{ + LabelsRefs: []uint32{1, 2}, + Exemplars: []writev2.Exemplar{{ + LabelsRefs: []uint32{}, + Value: 1.0, + Timestamp: 1, + }}, + }}, + writeV2RequestFixture.Timeseries...), + expectedCode: http.StatusBadRequest, + expectedRespBody: "TimeSeries must contain at least one sample or histogram for series {__name__=\"test_metric1\"}\n", + }, { desc: "Partial write; first series with one OOO sample", input: func() []writev2.TimeSeries {