{"record":{"id":"2e7d78fb462ee832","repo":"apache/beam","slug":"watch-allowed-lateness-must-not-be-negative-got-s","errorCode":null,"errorMessage":"Watch allowed_lateness must not be negative, got %s","messagePattern":"Watch allowed_lateness must not be negative, got (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/io/watch.py","lineNumber":861,"sourceCode":"    now_fn: clock used for termination decisions; tests can inject one.\n  \"\"\"\n  def __init__(\n      self,\n      poll_fn: Callable[[Any], PollResult],\n      poll_interval,\n      termination: Optional[TerminationCondition] = None,\n      output_coder: Optional[Coder] = None,\n      output_key_fn: Optional[Callable[[Any], Any]] = None,\n      output_key_coder: Optional[Coder] = None,\n      timestamp_cursor: bool = False,\n      allowed_lateness=0,\n      now_fn: Optional[Callable[[], float]] = None):\n    super().__init__()\n    if poll_interval is None:\n      raise ValueError('Watch requires a poll_interval')\n    allowed_lateness = _as_duration(allowed_lateness)\n    if allowed_lateness < Duration(0):\n      raise ValueError(\n          'Watch allowed_lateness must not be negative, got %s' %\n          allowed_lateness)\n    self._poll_fn = poll_fn\n    self._poll_interval = _as_duration(poll_interval)\n    self._termination = termination or never()\n    self._output_coder = output_coder\n    self._output_key_fn = output_key_fn\n    self._output_key_coder = output_key_coder\n    self._timestamp_cursor = timestamp_cursor\n    self._allowed_lateness = allowed_lateness\n    self._now = now_fn\n\n  def expand(self, pcoll):\n    output_coder = self._output_coder\n    if output_coder is None and isinstance(self._poll_fn, PollFn):\n      output_coder = self._poll_fn.default_output_coder()\n    if output_coder is None:\n      output_coder = _coder_for_hint(_poll_output_type(self._poll_fn))","sourceCodeStart":843,"sourceCodeEnd":879,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/io/watch.py#L843-L879","documentation":"Watch's allowed_lateness controls how long output produced after the watermark is still accepted. It is converted with _as_duration and validated to be non-negative; a negative Duration (or a negative convertible value) is rejected at construction time.","triggerScenarios":"Constructing beam.Watch or _Pollers with allowed_lateness=-5, a negative timedelta, or a negative string like '-10s' that _as_duration converts to a negative Duration.","commonSituations":"Configuration sign errors (subtracting lateness instead of adding); confusion with APIs where negative offsets mean something; loading negative values from pipeline options or YAML configs.","solutions":["Pass a non-negative duration, e.g. allowed_lateness=0 (default) or a positive value like allowed_lateness='1h'","Clamp or validate the config value before passing: max(0, configured_lateness)","If negative lateness was intended to disable lateness handling, use 0 instead"],"exampleFix":"// before\nbeam.Watch(poll_fn, poll_interval=10, allowed_lateness=-60)\n// after\nbeam.Watch(poll_fn, poll_interval=10, allowed_lateness=60)","handlingStrategy":"validation","validationCode":"lateness = _as_duration(allowed_lateness)\nif lateness < Duration(0):\n    raise ValueError('allowed_lateness must be >= 0')","typeGuard":"def is_valid_lateness(v) -> bool:\n    from apache_beam.utils.timestamp import Duration\n    try:\n        return _as_duration(v) >= Duration(0)\n    except Exception:\n        return False","tryCatchPattern":null,"preventionTips":["Validate durations loaded from configs/options before passing them to transforms","Remember allowed_lateness defaults to 0; only pass it when you need positive lateness","Use Beam duration helpers (_as_duration / '60s' strings) rather than raw negative numbers"],"tags":["python","apache-beam","invalid-argument-value","duration","watch-io"],"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-14T16:17:12.679Z"}