apache/beam · error · ValueError

fuzz parameter expected to be in [0, 1] range.

Error message

fuzz parameter expected to be in [0, 1] range.

What it means

RetryPolicy.__init__ validates the `fuzz` argument, which randomizes backoff delays to avoid thundering-herd retries; values outside [0, 1] would produce negative or magnified delays, so they are rejected at policy construction.

Solutions

  1. Pass fuzz as a fraction: 0 for no jitter, 0.5 for ±50%
  2. Clamp the value: fuzz = max(0.0, min(1.0, fuzz))
  3. Check config parsing if fuzz comes from a YAML/flag that supplies percent values

Example fix

// before
retry.WithFixedDelay(1, 60, fuzz=50)
// after
retry.WithFixedDelay(1, 60, fuzz=0.5)
Defensive patterns

Strategy: validation

Validate before calling

fuzz = max(0.0, min(1.0, float(fuzz)))
assert 0 <= fuzz <= 1

Try / catch

try:
    guard = retry.WithFixedDelay(1, 60, fuzz=fuzz)
except ValueError as e:
    logging.error('bad fuzz value: %s', e)
    guard = retry.WithFixedDelay(1, 60, fuzz=0.5)

Prevention

When it happens

Trigger: Constructing a retry guard with fuzz < 0 or fuzz > 1 (e.g. fuzz=2 intended as '2x jitter', or fuzz passed in percent like 50).

Common situations: Passing jitter as a percentage (50) or multiplier (1.5) instead of a fraction (0.5); sign errors from computed values.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/9723422b069ca488. Report an issue: GitHub.

Appendix: source

Thrown at sdks/python/apache_beam/utils/retry.py:106

      seconds), such that the sum is <= stop_after_secs. Defaults to disabled
      (None). You may need to increase num_retries to effectively use this
      feature.
  """
  def __init__(
      self,
      initial_delay_secs,
      num_retries,
      factor=2,
      fuzz=0.5,
      max_delay_secs=60 * 60 * 1,
      stop_after_secs=None):
    self._initial_delay_secs = initial_delay_secs
    if num_retries > 10000:
      raise ValueError('num_retries parameter cannot exceed 10000.')
    self._num_retries = num_retries
    self._factor = factor
    if not 0 <= fuzz <= 1:
      raise ValueError('fuzz parameter expected to be in [0, 1] range.')
    self._fuzz = fuzz
    self._max_delay_secs = max_delay_secs
    self._stop_after_secs = stop_after_secs

  def __iter__(self):
    current_delay_secs = min(self._max_delay_secs, self._initial_delay_secs)
    total_delay_secs = 0
    for _ in range(self._num_retries):
      fuzz_multiplier = 1 - self._fuzz + random.random() * self._fuzz
      delay_secs = current_delay_secs * fuzz_multiplier
      total_delay_secs += delay_secs
      if (self._stop_after_secs is not None and
          total_delay_secs > self._stop_after_secs):
        break
      yield delay_secs
      current_delay_secs = min(
          self._max_delay_secs, current_delay_secs * self._factor)

View on GitHub (pinned to 12126d8942)