diff --git a/model/histogram/generic.go b/model/histogram/generic.go index 327dada3ca..afd761bf4f 100644 --- a/model/histogram/generic.go +++ b/model/histogram/generic.go @@ -38,6 +38,7 @@ var ( ErrHistogramCustomBucketsMismatch = errors.New("histogram custom bounds are too few") ErrHistogramCustomBucketsInvalid = errors.New("histogram custom bounds must be in strictly increasing order") ErrHistogramCustomBucketsInfinite = errors.New("histogram custom bounds must be finite") + ErrHistogramCustomBucketsNaN = errors.New("histogram custom bounds must not be NaN") ErrHistogramsIncompatibleSchema = errors.New("cannot apply this operation on histograms with a mix of exponential and custom bucket schemas") ErrHistogramsIncompatibleBounds = errors.New("cannot apply this operation on custom buckets histograms with different custom bounds") ErrHistogramCustomBucketsZeroCount = errors.New("custom buckets: must have zero count of 0") @@ -454,6 +455,9 @@ func checkHistogramBuckets[BC BucketCount, IBC InternalBucketCount](buckets []IB func checkHistogramCustomBounds(bounds []float64, spans []Span, numBuckets int) error { prev := math.Inf(-1) for _, curr := range bounds { + if math.IsNaN(curr) { + return ErrHistogramCustomBucketsNaN + } if curr <= prev { return fmt.Errorf("previous bound is %f and current is %f: %w", prev, curr, ErrHistogramCustomBucketsInvalid) } diff --git a/model/histogram/histogram_test.go b/model/histogram/histogram_test.go index 52a3392154..9b93b3581c 100644 --- a/model/histogram/histogram_test.go +++ b/model/histogram/histogram_test.go @@ -1565,6 +1565,27 @@ func TestHistogramValidation(t *testing.T) { CustomValues: []float64{1, 2, 3, 4, 5, 6, 7, 8}, }, }, + "reject custom buckets histogram with non-increasing bound": { + h: &Histogram{ + Schema: CustomBucketsSchema, + CustomValues: []float64{0, 0}, + }, + errMsg: "custom buckets: previous bound is 0.000000 and current is 0.000000: histogram custom bounds must be in strictly increasing order", + }, + "reject custom buckets histogram with explicit +Inf bound": { + h: &Histogram{ + Schema: CustomBucketsSchema, + CustomValues: []float64{1, math.Inf(1)}, + }, + errMsg: "custom buckets: last +Inf bound must not be explicitly defined: histogram custom bounds must be finite", + }, + "reject custom buckets histogram with NaN bound": { + h: &Histogram{ + Schema: CustomBucketsSchema, + CustomValues: []float64{1, math.NaN(), 3}, + }, + errMsg: "custom buckets: histogram custom bounds must not be NaN", + }, "schema too high": { h: &Histogram{ Schema: 10, diff --git a/storage/remote/write_handler.go b/storage/remote/write_handler.go index d134fc9403..a7cd82ffc0 100644 --- a/storage/remote/write_handler.go +++ b/storage/remote/write_handler.go @@ -129,6 +129,7 @@ func isHistogramValidationError(err error) bool { errors.Is(err, histogram.ErrHistogramCustomBucketsMismatch) || errors.Is(err, histogram.ErrHistogramCustomBucketsInvalid) || errors.Is(err, histogram.ErrHistogramCustomBucketsInfinite) || + errors.Is(err, histogram.ErrHistogramCustomBucketsNaN) || errors.Is(err, histogram.ErrHistogramCustomBucketsZeroCount) || errors.Is(err, histogram.ErrHistogramCustomBucketsZeroThresh) || errors.Is(err, histogram.ErrHistogramCustomBucketsNegSpans) ||