apache/beam · error · ValueError
key value is out of range
Error message
key value %d is out of range
What it means
Timers in the worker are indexed by a timestamp in microseconds, and this map-like structure enforces a valid timestamp range (RANGE_MIN..RANGE_MAX, derived from the 8-byte key encoding). A TimerMap.add() with a timestamp micros value outside that range raises ValueError. It guards against timestamps that cannot round-trip through the backing store.
Solutions
- Clamp the timer timestamp to the valid range before setting (e.g. cap at a safe max like 2262-04-11)
- Use a realistic event-time timestamp instead of datetime.max/min sentinels
- Adjust window/trigger logic so timers fire within representable range
- Add a validation step that rejects out-of-range event times upstream
Example fix
// before TimerSpec.set_timer(w, 'cleanup', firing_time=datetime.max) // after max_ts = datetime.datetime(2262, 4, 11) TimerSpec.set_timer(w, 'cleanup', firing_time=min(firing_time, max_ts))
Defensive patterns
Strategy: validation
Validate before calling
import apache_beam.utils.timestamp as ts
RANGE_MIN, RANGE_MAX = -9223372036854, 9223372036854 # per worker TimerMap bounds
def timer_ts_ok(dt):
micros = ts.Timestamp.from_rfc3339(dt.isoformat()).micros if hasattr(dt, 'isoformat') else int(dt) * 1_000_000
return RANGE_MIN <= micros < RANGE_MAX
# call before set_timer; clamp firing_time otherwise Try / catch
try:
ctx.set_timer('cleanup', firing_time)
except ValueError as e:
if 'key value' in str(e) and 'out of range' in str(e):
logging.warning('Timer timestamp %s out of range; clamping', firing_time)
ctx.set_timer('cleanup', min(max(firing_time, min_ts), max_ts))
else:
raise Prevention
- Never use datetime.max/min as timer timestamps; use clamped sentinels
- Validate event times at pipeline entry (reject or clamp extremes)
- Remember representable range roughly ±292,000 years in micros vs. practical window bounds
- Add unit tests for timers at boundary timestamps
When it happens
Trigger: Calling add() on the timer state map with a Timestamp whose .micros exceeds RANGE_MAX or is below RANGE_MIN — e.g. timer set at an extreme timestamp (far past/far future) like 9999-12-31 or negative epoch values.
Common situations: Setting timers at datetime.max/min sentinels; using windows with enormous allowed timestamps; negative timestamps from bad event-time parsing.
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
- Unexpected time domain
- A BigQuery table or a query must be specified
- A cluster_identifier should be Optional[Union[str…
- A context manager constructor (not a fully constructed…
- A has been supplied to the model handler, but the required…
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/05ac5727582b9696.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/python/apache_beam/runners/worker/bundle_processor.py:780
self,
state_handler: sdk_worker.CachingStateHandler,
state_key: beam_fn_api_pb2.StateKey,
value_coder: coders.Coder) -> None:
self._state_handler = state_handler
self._state_key = state_key
self._elem_coder = beam.coders.TupleCoder(
[coders.VarIntCoder(), coders.coders.LengthPrefixCoder(value_coder)])
self._cleared = False
self._pending_adds = SortedDict()
self._pending_removes = RangeSet()
def add(self, elem: tuple[timestamp.Timestamp, Any]) -> None:
assert len(elem) == 2
key_ts, value = elem
key = key_ts.micros
if key >= self.RANGE_MAX or key < self.RANGE_MIN:
raise ValueError("key value %d is out of range" % key)
self._pending_adds.setdefault(key, []).append(value)
def read(self) -> Iterable[tuple[timestamp.Timestamp, Any]]:
return self.read_range(self.TIMESTAMP_RANGE_MIN, self.TIMESTAMP_RANGE_MAX)
def read_range(
self,
min_timestamp: timestamp.Timestamp,
limit_timestamp: timestamp.Timestamp
) -> Iterable[tuple[timestamp.Timestamp, Any]]:
# convert timestamp to int, as sort keys are stored as int internally.
min_key = min_timestamp.micros
limit_key = limit_timestamp.micros
keys_to_add = self._pending_adds.irange(
min_key, limit_key, inclusive=(True, False))
# use list interpretation here to construct the actual listView on GitHub (pinned to 12126d8942)