{"record":{"id":"621e3fe3c701b3d5","repo":"apache/beam","slug":"distribution-counters-support-only-non-negative-value","errorCode":null,"errorMessage":"Distribution counters support only non-negative value","messagePattern":"Distribution counters support only non-negative value","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/transforms/py_dataflow_distribution_counter.py","lineNumber":92,"sourceCode":"  \"\"\"\n  # Assume the max input is sys.maxint, then the possible max bucket size is 59\n  MAX_BUCKET_SIZE = 59\n\n  # 3 buckets for every power of ten -> 1, 2, 5\n  BUCKET_PER_TEN = 3\n\n  def __init__(self):\n    global INT64_MAX  # pylint: disable=global-variable-not-assigned\n    self.min = INT64_MAX\n    self.max = 0\n    self.count = 0\n    self.sum = 0\n    self.buckets = [0] * self.MAX_BUCKET_SIZE\n    self.is_cythonized = False\n\n  def add_input(self, element):\n    if element < 0:\n      raise ValueError('Distribution counters support only non-negative value')\n    self.min = min(self.min, element)\n    self.max = max(self.max, element)\n    self.count += 1\n    self.sum += element\n    bucket_index = self.calculate_bucket_index(element)\n    self.buckets[bucket_index] += 1\n\n  def add_input_n(self, element, n):\n    if element < 0:\n      raise ValueError('Distribution counters support only non-negative value')\n    self.min = min(self.min, element)\n    self.max = max(self.max, element)\n    self.count += n\n    self.sum += element * n\n    bucket_index = self.calculate_bucket_index(element)\n    self.buckets[bucket_index] += n\n\n  def calculate_bucket_index(self, element):","sourceCodeStart":74,"sourceCodeEnd":110,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/transforms/py_dataflow_distribution_counter.py#L74-L110","documentation":"The Dataflow Distribution counter only supports non-negative values (it models Google Cloud Dataflow distribution metrics whose buckets assume non-negative inputs). add_input() validates this and raises ValueError for negative elements.","triggerScenarios":"Calling `DistributionCounter().add_input(x)` with x < 0, e.g. aggregating deltas, signed temperatures, or error codes that can be negative.","commonSituations":"Metric aggregation code computing diffs (before/after), signed sensor data, or countdown values fed directly into a Dataflow distribution counter.","solutions":["Clamp or filter negative values before adding: `counter.add_input(max(0, x))` if semantics allow.","Track negative values separately (e.g. count of negatives in a separate counter) and add absolutes if distribution of magnitude is what matters.","Use a different aggregation (Sum counter, custom accumulator) that supports signed values if negatives are legitimate."],"exampleFix":"# before\nfor delta in deltas:\n  dist.add_input(delta)\n# after\nfor delta in deltas:\n  dist.add_input(max(0, delta))","handlingStrategy":"validation","validationCode":"if x < 0:\n  raise ValueError(f'{x} cannot be added to a distribution counter')","typeGuard":"def is_non_negative_int(v):\n  return isinstance(v, int) and not isinstance(v, bool) and v >= 0","tryCatchPattern":"try:\n  dist.add_input(value)\nexcept ValueError as e:\n  log.warning('Skipping negative distribution input: %s', e)","preventionTips":["Filter or clamp negatives before metric aggregation.","Track signed quantities with separate sum/min/max counters, not Dataflow distributions.","Add a unit test feeding domain extremes (including negatives) through counter code."],"tags":["python","apache-beam","counters","dataflow"],"backgroundTag":"invalid-argument-value","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"}