apache/beam · error · ValueError

The timestamp of deter_remainder() should be a Duration or a

Error message

The timestamp of deter_remainder() should be a Duration or a Timestamp, or None.

What it means

ThreadsafeRestrictionTracker.defer_remainder() accepts an optional deferred_time used to report how long the remainder is deferred. If a truthy value is passed that is neither a Duration nor a Timestamp, this ValueError is raised before checkpointing the remainder.

Source

Thrown at sdks/python/apache_beam/runners/sdf_utils.py:99

    Self-checkpoint could happen during processing elements. When executing an
    DoFn.process(), you may want to stop processing an element and resuming
    later if current element has been processed quit a long time or you also
    want to have some outputs from other elements. ``defer_remainder()`` can be
    called on per element if needed.

    Args:
      deferred_time: A relative ``Duration`` that indicates the ideal time gap
        between now and resuming, or an absolute ``Timestamp`` for resuming
        execution time. If the time_delay is None, the deferred work will be
        executed as soon as possible.
    """

    # Record current time for calculating deferred_time later.
    with self._lock:
      self._timestamp = Timestamp.now()
      if deferred_time and not isinstance(deferred_time, (Duration, Timestamp)):
        raise ValueError(
            'The timestamp of deter_remainder() should be a '
            'Duration or a Timestamp, or None.')
      self._deferred_timestamp = deferred_time
      checkpoint = self.try_split(0)
      if checkpoint:
        _, self._deferred_residual = checkpoint

  def check_done(self):
    with self._lock:
      return self._restriction_tracker.check_done()

  def current_progress(self) -> 'RestrictionProgress':
    with self._lock:
      return self._restriction_tracker.current_progress()

  def try_split(self, fraction_of_remainder):
    with self._lock:
      return self._restriction_tracker.try_split(fraction_of_remainder)

View on GitHub (pinned to 12126d8942)

Solutions

  1. Convert the value to apache_beam.utils.timestamp.Duration (or Timestamp) before calling defer_remainder
  2. Pass None to defer without an explicit deferred time
  3. Use Timestamp.of()/Duration(seconds=...) helpers for correct types

Example fix

// before
tracker.defer_remainder(30)
// after
from apache_beam.utils.timestamp import Duration
tracker.defer_remainder(Duration(seconds=30))
Defensive patterns

Strategy: type-guard

Validate before calling

from apache_beam.utils.timestamp import Duration, Timestamp
assert deferred_time is None or isinstance(deferred_time, (Duration, Timestamp))

Type guard

from apache_beam.utils.timestamp import Duration, Timestamp
def is_deferred_time(x) -> bool:
    return x is None or isinstance(x, (Duration, Timestamp))

Try / catch

try:
    tracker.defer_remainder(dt)
except ValueError as e:
    if 'Duration or a Timestamp' in str(e):
        tracker.defer_remainder(None)
    else:
        raise

Prevention

When it happens

Trigger: Calling tracker.defer_remainder(x) where x is truthy but of an unexpected type — e.g. an int, float, datetime.timedelta, or string — instead of apache_beam.utils.timestamp.Duration or Timestamp (or None/0/falsy).

Common situations: Passing datetime.timedelta or seconds-as-number from user code that schedules deferral; confusing Duration vs Timestamp units when wiring a custom splittable DoFn.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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