microsoft/aspire · error · InvalidOperationException

Histogram data point bucket count length changed.

Error message

Histogram data point bucket count length changed.

What it means

DimensionScope.AddHistogramValue accumulates cumulative histogram data points by subtracting the previous bucket counts. If a new point's bucket count differs from the last stored HistogramValue's layout, cumulative deltas cannot be computed, so it throws InvalidOperationException. The series is only usable when bucket layouts stay stable.

Solutions

  1. Keep histogram bucket boundaries constant for a given instrument across restarts while the dashboard is aggregating
  2. Restart the dashboard (clearing the in-memory series) after changing bucket configuration
  3. Ensure all instances producing the same instrument name/dimensions use identical bucket boundaries
  4. Check collector configs for processors that rewrite histogram buckets and remove or align them

Example fix

// before
var boundaries = changingDeployments ? new[] { 0d, 10d, 100d } : new[] { 0d, 5d, 50d }; // layout varies
// after
private static readonly double[] BucketBoundaries = { 0d, 5d, 50d }; // stable per series
Defensive patterns

Strategy: validation

Validate before calling

if (previous is HistogramValue pv && pv.Values.Length != current.BucketCounts.Count)
    throw new InvalidOperationException("Bucket layout changed; reset the series before aggregating.");

Try / catch

try
{
    dimensionScope.AddHistogramValue(point, context);
}
catch (InvalidOperationException ex) when (ex.Message.Contains("bucket count length changed"))
{
    logger.LogWarning(ex, "Dropping histogram series with changed bucket layout.");
}

Prevention

When it happens

Trigger: A metrics stream for the same instrument/dimensions where a data point's ExplicitBounds (and thus BucketCounts) changes mid-series — e.g. the producer changed the histogram boundary configuration, or the collector remapped buckets between exports.

Common situations: Changing bucket boundaries in the app's meter configuration and redeploying while the dashboard keeps the old series; two producers exporting the same instrument name with different bucket definitions; collector transformations altering histogram buckets.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/4a3e4df09ef98471. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Dashboard/Otlp/Model/MetricValues/DimensionScope.cs:92

                _lastValue = new MetricValue<double>(d.AsDouble, start, end);
                AddExemplars(_lastValue, d.Exemplars, context);
                _values.Add(_lastValue);
            }
        }
    }

    public void AddHistogramValue(HistogramDataPoint h, OtlpContext context)
    {
        var start = OtlpHelpers.UnixNanoSecondsToDateTime(h.StartTimeUnixNano);
        var end = OtlpHelpers.UnixNanoSecondsToDateTime(h.TimeUnixNano);
        OtlpHelpers.ValidateHistogramDataPoint(h);

        var lastHistogramValue = _lastValue as HistogramValue;
        if (lastHistogramValue is not null && lastHistogramValue.Values.Length != h.BucketCounts.Count)
        {
            // Histogram bucket layouts must remain stable within a series so cumulative values can
            // be subtracted and combined. A changed bucket count would make the series unusable.
            throw new InvalidOperationException("Histogram data point bucket count length changed.");
        }

        if (lastHistogramValue is not null && lastHistogramValue.Count == h.Count)
        {
            lastHistogramValue.End = end;
            AddExemplars(lastHistogramValue, h.Exemplars, context);
        }
        else
        {
            // If the explicit bounds are the same as the last value, reuse them.
            double[] explicitBounds;
            if (lastHistogramValue is not null)
            {
                start = lastHistogramValue.End;
                explicitBounds = lastHistogramValue.ExplicitBounds.SequenceEqual(h.ExplicitBounds)
                    ? lastHistogramValue.ExplicitBounds
                    : h.ExplicitBounds.ToArray();
            }

View on GitHub (pinned to 25830f84bd)