{"record":{"id":"f9b991ccbf8fa8e0","repo":"apache/beam","slug":"failed-to-combine-histogram","errorCode":null,"errorMessage":"failed to combine histogram.","messagePattern":"failed to combine histogram\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/utils/histogram.py","lineNumber":58,"sourceCode":"    with self._lock:\n      self._buckets = Counter()\n      self._num_records = 0\n      self._num_top_records = 0\n      self._num_bot_records = 0\n\n  def copy(self):\n    with self._lock:\n      histogram = Histogram(self._bucket_type)\n      histogram._num_records = self._num_records\n      histogram._num_top_records = self._num_top_records\n      histogram._num_bot_records = self._num_bot_records\n      histogram._buckets = self._buckets.copy()\n      return histogram\n\n  def combine(self, other):\n    if not isinstance(other,\n                      Histogram) or self._bucket_type != other._bucket_type:\n      raise RuntimeError('failed to combine histogram.')\n    other_histogram = other.copy()\n    with self._lock:\n      histogram = Histogram(self._bucket_type)\n      histogram._num_records = self._num_records + other_histogram._num_records\n      histogram._num_top_records = (\n          self._num_top_records + other_histogram._num_top_records)\n      histogram._num_bot_records = (\n          self._num_bot_records + other_histogram._num_bot_records)\n      histogram._buckets = self._buckets + other_histogram._buckets\n      return histogram\n\n  def record(self, *args):\n    for arg in args:\n      self._record(arg)\n\n  def _record(self, value):\n    range_from = self._bucket_type.range_from()\n    range_to = self._bucket_type.range_to()","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/utils/histogram.py#L40-L76","documentation":"Histogram.combine only supports merging another Histogram instance using the identical bucket type (linear vs logarithmic). Passing a non-Histogram or a differently-bucketed histogram makes the merge meaningless, so Beam raises RuntimeError. This surfaces in distributed aggregation when partial histograms are combined.","triggerScenarios":"Calling h1.combine(h2) where h2 is not a Histogram, or h1 uses HistogramLinearBuckets while h2 uses HistogramLogBuckets.","commonSituations":"Aggregating metrics where different transforms were configured with different bucket strategies; mixing old serialized histograms with new bucket configs after a config change; passing a dict or namedtuple representing histogram data.","solutions":["Ensure all histograms use the same bucket type before combining.","Recreate histograms from raw data with a uniform bucket type if mismatched.","Convert buckets explicitly (re-bin) before merging if approximation is acceptable.","Check isinstance(other, Histogram) and bucket_type equality at call sites."],"exampleFix":"// before\nh1 = Histogram(HistogramLinearBuckets(...)); h2 = Histogram(HistogramLogBuckets(...))\nh1.combine(h2)\n// after\nh2 = Histogram(HistogramLinearBuckets(...))  # same bucket type as h1\nh1.combine(h2)","handlingStrategy":"type-guard","validationCode":"from apache_beam.utils.histogram import Histogram\nif not isinstance(other, Histogram) or h1._bucket_type != other._bucket_type:\n    raise TypeError('histograms must share bucket type')","typeGuard":"def can_combine(h1, h2) -> bool:\n    return isinstance(h2, Histogram) and h1._bucket_type == h2._bucket_type","tryCatchPattern":"try:\n    combined = h1.combine(h2)\nexcept RuntimeError:\n    combined = None  # rebuild from raw samples with one bucket type","preventionTips":["Centralize bucket-type creation so all histograms share it","Don't change bucket configs mid-flight in running pipelines","Assert bucket types match when merging partial aggregates"],"tags":["python","apache-beam","histogram","metrics"],"backgroundTag":"incompatible-source-type","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}