{"record":{"id":"bbd1918a11dd961c","repo":"apache/beam","slug":"poll-interval-must-be-0-got-r","errorCode":null,"errorMessage":"poll_interval must be >= 0, got %r","messagePattern":"poll_interval must be >= 0, got %r","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/io/unbounded_source.py","lineNumber":955,"sourceCode":"  \"\"\"\n  def __init__(\n      self,\n      source: UnboundedSource,\n      poll_interval: float = _DEFAULT_POLL_INTERVAL_SECONDS,\n      max_records_per_bundle: int = _DEFAULT_MAX_RECORDS_PER_BUNDLE,\n      max_read_time_seconds: float = _DEFAULT_MAX_READ_TIME_SECONDS):\n    if not isinstance(source, UnboundedSource):\n      raise TypeError('source must be an UnboundedSource, got %r' % (source, ))\n    if max_records_per_bundle < 1:\n      raise ValueError(\n          'max_records_per_bundle must be >= 1, got %r' %\n          (max_records_per_bundle, ))\n    if max_read_time_seconds <= 0:\n      raise ValueError(\n          'max_read_time_seconds must be > 0, got %r' %\n          (max_read_time_seconds, ))\n    if poll_interval < 0:\n      raise ValueError(\n          'poll_interval must be >= 0, got %r' % (poll_interval, ))\n    super().__init__()\n    self._source = source\n    self._poll_interval = poll_interval\n    self._max_records_per_bundle = max_records_per_bundle\n    self._max_read_time_seconds = max_read_time_seconds\n\n  def expand(self, pbegin):\n    source = self._source\n    output_coder = source.default_output_coder()\n    # The source is the SDF element used to derive the initial restriction.\n    # process() reads from the restriction, so it does not use the element\n    # directly.\n    output = (\n        pbegin\n        | 'Create' >> core.Create([source])\n        | 'ReadUnbounded' >> core.ParDo(\n            _ReadFromUnboundedSourceDoFn(","sourceCodeStart":937,"sourceCodeEnd":973,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/io/unbounded_source.py#L937-L973","documentation":"poll_interval controls how long the reader sleeps between polls of the unbounded source; it must be non-negative. The constructor raises ValueError for negative values, since a negative sleep interval is meaningless and would break the polling loop.","triggerScenarios":"Initializing the reader with poll_interval < 0, e.g. from a misparsed config ('-1'), or a computed interval that went negative.","commonSituations":"Using -1 as a 'default/disable' sentinel (use 0 instead); parsing a duration with a sign error; subtracting timestamps to derive the interval and getting a negative value.","solutions":["Pass poll_interval >= 0 (0 means poll continuously without sleeping)","Clamp the value: poll_interval=max(0.0, configured_value)","Fix the config parsing or computation that produced the negative number"],"exampleFix":"# before\nreader = Reader(source, poll_interval=-1)\n# after\nreader = Reader(source, poll_interval=max(0.0, configured_interval))","handlingStrategy":"validation","validationCode":"if float(poll_interval) < 0:\n    raise ValueError('poll_interval must be >= 0')","typeGuard":null,"tryCatchPattern":"try:\n    reader = Reader(source, poll_interval=p)\nexcept ValueError:\n    reader = Reader(source, poll_interval=0.0)  # poll without sleeping","preventionTips":["Use 0, not -1, as the neutral/default sentinel","Clamp parsed intervals: max(0.0, value)","Check sign handling in duration parsing code"],"tags":["python","apache-beam","validation","config"],"backgroundTag":"invalid-config-value","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-14T21:17:11.552Z"}