{"record":{"id":"ee54a41df9156c5b","repo":"apache/beam","slug":"percentile-should-be-between-0-and-1","errorCode":null,"errorMessage":"percentile should be between 0 and 1.","messagePattern":"percentile should be between 0 and 1\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/utils/histogram.py","lineNumber":136,"sourceCode":"                _format(self._get_linear_interpolation(0.90)),\n                _format(self._get_linear_interpolation(0.50))))\n      else:\n        return ('Total count: %s' % (self.total_count(), ))\n\n  def get_linear_interpolation(self, percentile):\n    \"\"\"Calculate percentile estimation based on linear interpolation.\n\n    It first finds the bucket which includes the target percentile and\n    projects the estimated point in the bucket by assuming all the elements\n    in the bucket are uniformly distributed.\n\n    Args:\n      percentile: The target percentile of the value returning from this\n        method. Should be a floating point number greater than 0 and less\n        than 1.\n    \"\"\"\n    if percentile > 1 or percentile < 0:\n      raise ValueError('percentile should be between 0 and 1.')\n    with self._lock:\n      return self._get_linear_interpolation(percentile)\n\n  def _get_linear_interpolation(self, percentile):\n    total_num_records = self.total_count()\n    if total_num_records == 0:\n      raise RuntimeError('histogram has no record.')\n\n    index = 0\n    record_sum = self._num_bot_records\n    if record_sum / total_num_records >= percentile:\n      return float('-inf')\n    while index < self._bucket_type.num_buckets():\n      record_sum += self._buckets.get(index, 0)\n      if record_sum / total_num_records >= percentile:\n        break\n      index += 1\n    if index == self._bucket_type.num_buckets():","sourceCodeStart":118,"sourceCodeEnd":154,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/utils/histogram.py#L118-L154","documentation":"Histogram percentile queries (p50/p90/p99 via get_linear_interpolation) require a percentile in [0, 1]. Values outside this range have no defined quantile, so Beam raises ValueError before computing. Note the check rejects exactly 1 via percentile > 1, allowing 1 but the docstring recommends (0, 1).","triggerScenarios":"Calling h.p99(percentile=1.5) or get_linear_interpolation(-0.1); passing percentages (e.g. 90) instead of fractions (0.9); bad config-driven percentile values.","commonSituations":"Confusing percent (0-100) with fraction (0-1); NaN sneaking past comparisons and then failing downstream; user-supplied percentile parameters unvalidated.","solutions":["Express percentiles as fractions: 0.5 for p50, 0.99 for p99.","Clamp input: percentile = min(max(p, 0.0), 1.0).","Convert user-facing percent inputs: p / 100.0 before calling.","Reject invalid values at the configuration boundary."],"exampleFix":"// before\nh.get_linear_interpolation(95)  # meant 95th percentile\n// after\nh.get_linear_interpolation(0.95)","handlingStrategy":"validation","validationCode":"if not (0.0 <= percentile <= 1.0):\n    raise ValueError('percentile must be a fraction in [0, 1]')","typeGuard":null,"tryCatchPattern":"try:\n    v = h.p99(percentile=p)\nexcept ValueError:\n    v = h.p99(percentile=min(max(p, 0.0), 1.0))","preventionTips":["Store percentiles as fractions (0.5, 0.9, 0.99) everywhere","Convert percent (0-100) inputs with p / 100.0 at boundaries","Beware NaN: validate with math.isfinite before use"],"tags":["python","apache-beam","histogram","percentile"],"backgroundTag":"value-out-of-range","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"}