apache/beam · error · RuntimeError
Cache tokens already set to
Error message
Cache tokens already set to %s
What it means
CachingStateHandler.process_instruction_id sets the per-instruction cache tokens (user_state_cache_token and side_input_cache_tokens). If the thread context still has a user_state_cache_token from a previous bundle that was not cleared, it raises 'Cache tokens already set to %s', guarding against cache token collisions between bundles.
Solutions
- Ensure each `with handler.process_instruction_id(...)` completes before the next begins
- Restart/retry the bundle to clear leaked thread-local state
- Verify only one bundle is executed per harness thread at a time; upgrade Beam if a token-reset bug is present
Example fix
// before
with handler.process_instruction_id(bundle_a, tokens):
with handler.process_instruction_id(bundle_b, tokens2): # raises
...
// after
with handler.process_instruction_id(bundle_a, tokens):
...
with handler.process_instruction_id(bundle_b, tokens2):
... Defensive patterns
Strategy: try-catch
Validate before calling
if getattr(handler._context, 'user_state_cache_token', None) is not None: raise StateError('cache token still bound') Type guard
def cache_token_bound(handler): return getattr(handler._context, 'user_state_cache_token', None) is not None
Try / catch
try:
with handler.process_instruction_id(bundle_id, cache_tokens):
...
except RuntimeError as e:
if str(e).startswith('Cache tokens already set'):
log.error('leaked cache token context: %s', e)
raise Prevention
- Process one bundle at a time per handler
- Ensure cache-token context managers always exit (finally)
- Check runner for concurrent instruction dispatch bugs
When it happens
Trigger: Entering process_instruction_id twice without the previous contextmanager exiting; exception paths skipping the finally-reset of user_state_cache_token; a runner sending cache tokens for overlapping instructions on the same handler.
Common situations: Runner bugs reusing bundle contexts; leaked context bindings after exceptions; shared thread-local state across bundles.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Already bound to %r
- Cannot schedule new tasks after thread pool has been…
- Encountered exceptions in finalize_write
- Timeout waiting to acquire model
- Unable to handle state requests for ProcessBundleDescriptor…
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/62d1124b8ec77068.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/python/apache_beam/runners/worker/sdk_worker.py:1196
self,
global_state_cache, # type: StateCache
underlying_state # type: StateHandler
):
# type: (...) -> None
self._underlying = underlying_state
self._state_cache = global_state_cache
self._context = threading.local()
# state retrieval time statistics
self._retrieval_time = 0.0
self._get_raw_called = 0
self._warn_interval = 60.0
@contextlib.contextmanager
def process_instruction_id(self, bundle_id, cache_tokens):
# type: (str, Iterable[beam_fn_api_pb2.ProcessBundleRequest.CacheToken]) -> Iterator[None]
if getattr(self._context, 'user_state_cache_token', None) is not None:
raise RuntimeError(
'Cache tokens already set to %s' %
self._context.user_state_cache_token)
self._context.side_input_cache_tokens = {}
user_state_cache_token = None
for cache_token_struct in cache_tokens:
if cache_token_struct.HasField("user_state"):
# There should only be one user state token present
assert not user_state_cache_token
user_state_cache_token = cache_token_struct.token
elif cache_token_struct.HasField("side_input"):
self._context.side_input_cache_tokens[
cache_token_struct.side_input.transform_id,
cache_token_struct.side_input.
side_input_id] = cache_token_struct.token
# TODO: Consider a two-level cache to avoid extra logic and locking
# for items cached at the bundle level.
self._context.bundle_cache_token = bundle_id
try:View on GitHub (pinned to 12126d8942)