{"record":{"id":"4a3e4df09ef98471","repo":"microsoft/aspire","slug":"histogram-data-point-bucket-count-length-changed","errorCode":null,"errorMessage":"Histogram data point bucket count length changed.","messagePattern":"Histogram data point bucket count length changed\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Dashboard/Otlp/Model/MetricValues/DimensionScope.cs","lineNumber":92,"sourceCode":"                _lastValue = new MetricValue<double>(d.AsDouble, start, end);\n                AddExemplars(_lastValue, d.Exemplars, context);\n                _values.Add(_lastValue);\n            }\n        }\n    }\n\n    public void AddHistogramValue(HistogramDataPoint h, OtlpContext context)\n    {\n        var start = OtlpHelpers.UnixNanoSecondsToDateTime(h.StartTimeUnixNano);\n        var end = OtlpHelpers.UnixNanoSecondsToDateTime(h.TimeUnixNano);\n        OtlpHelpers.ValidateHistogramDataPoint(h);\n\n        var lastHistogramValue = _lastValue as HistogramValue;\n        if (lastHistogramValue is not null && lastHistogramValue.Values.Length != h.BucketCounts.Count)\n        {\n            // Histogram bucket layouts must remain stable within a series so cumulative values can\n            // be subtracted and combined. A changed bucket count would make the series unusable.\n            throw new InvalidOperationException(\"Histogram data point bucket count length changed.\");\n        }\n\n        if (lastHistogramValue is not null && lastHistogramValue.Count == h.Count)\n        {\n            lastHistogramValue.End = end;\n            AddExemplars(lastHistogramValue, h.Exemplars, context);\n        }\n        else\n        {\n            // If the explicit bounds are the same as the last value, reuse them.\n            double[] explicitBounds;\n            if (lastHistogramValue is not null)\n            {\n                start = lastHistogramValue.End;\n                explicitBounds = lastHistogramValue.ExplicitBounds.SequenceEqual(h.ExplicitBounds)\n                    ? lastHistogramValue.ExplicitBounds\n                    : h.ExplicitBounds.ToArray();\n            }","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Dashboard/Otlp/Model/MetricValues/DimensionScope.cs#L74-L110","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Keep histogram bucket boundaries constant for a given instrument across restarts while the dashboard is aggregating","Restart the dashboard (clearing the in-memory series) after changing bucket configuration","Ensure all instances producing the same instrument name/dimensions use identical bucket boundaries","Check collector configs for processors that rewrite histogram buckets and remove or align them"],"exampleFix":"// before\nvar boundaries = changingDeployments ? new[] { 0d, 10d, 100d } : new[] { 0d, 5d, 50d }; // layout varies\n// after\nprivate static readonly double[] BucketBoundaries = { 0d, 5d, 50d }; // stable per series","handlingStrategy":"validation","validationCode":"if (previous is HistogramValue pv && pv.Values.Length != current.BucketCounts.Count)\n    throw new InvalidOperationException(\"Bucket layout changed; reset the series before aggregating.\");","typeGuard":null,"tryCatchPattern":"try\n{\n    dimensionScope.AddHistogramValue(point, context);\n}\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"bucket count length changed\"))\n{\n    logger.LogWarning(ex, \"Dropping histogram series with changed bucket layout.\");\n}","preventionTips":["Fix explicit histogram boundaries once per instrument and never change them mid-deployment","Restart the dashboard after changing bucket configuration","Ensure all producers of the same instrument use identical bucket definitions"],"tags":["metrics","histogram","invariant","dashboard"],"backgroundTag":"internal-invariant-violation","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T09:17:21.228Z"}