{"record":{"id":"a8d4d2ca10022d7f","repo":"apache/beam","slug":"entry-was-released","errorCode":null,"errorMessage":"Entry was released.","messagePattern":"Entry was released\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/utils/multi_process_shared.py","lineNumber":79,"sourceCode":"multiprocessing.managers.AutoProxy = patched_autoproxy  # type: ignore[attr-defined]\n\nT = TypeVar('T')\nAUTH_KEY = b'mps'\n\n\nclass _SingletonProxy:\n  \"\"\"Proxies the shared object so we can release it with better errors and no\n  risk of dangling references in the multiprocessing manager infrastructure.\n  \"\"\"\n  def __init__(self, entry):\n    # Guard names so as to not conflict with names of underlying object.\n    self._SingletonProxy_entry = entry\n    self._SingletonProxy_valid = True\n\n  # Used to make the shared object callable (see _AutoProxyWrapper below)\n  def singletonProxy_call__(self, *args, **kwargs):\n    if not self._SingletonProxy_valid:\n      raise RuntimeError('Entry was released.')\n    return self._SingletonProxy_entry.obj.__call__(*args, **kwargs)\n\n  def singletonProxy_release(self):\n    assert self._SingletonProxy_valid\n    self._SingletonProxy_valid = False\n\n  def singletonProxy_unsafe_hard_delete(self):\n    assert self._SingletonProxy_valid\n    self._SingletonProxy_entry.unsafe_hard_delete()\n\n  def __getattr__(self, name):\n    if not self._SingletonProxy_valid:\n      raise RuntimeError('Entry was released.')\n    try:\n      return getattr(self._SingletonProxy_entry.obj, name)\n    except AttributeError as e:\n      # Swallow AttributeError exceptions so that they are ignored when\n      # calculating public functions. These can occur if __getattr__ is","sourceCodeStart":61,"sourceCodeEnd":97,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/utils/multi_process_shared.py#L61-L97","documentation":"In apache_beam.utils.multi_process_shared, a SingletonProxy wraps a shared object and tracks validity; singletonProxy_release() invalidates the proxy when the shared entry is released. Any subsequent call through the proxy (e.g. calling the shared object) raises RuntimeError('Entry was released.') because the underlying shared object is no longer available in this process.","triggerScenarios":"Holding a reference obtained via multi_process_shared.SharedAcquirer/MultiProcessShared, then calling it after the entry was released (release() called, or the shared handle's context/with-block exited) from another thread or retained closure.","commonSituations":"Using the shared object after leaving `with multi_process_shared.MultiProcessShared(...) as ...` scope; sharing a callable across threads where one thread releases while another still calls; caching the proxy beyond its intended lifetime in DirectRunner multiprocess modes.","solutions":["Re-acquire the shared entry via MultiProcessShared/SharedAcquirer before calling it again instead of reusing a stale proxy.","Keep all uses of the shared object inside the scope where the entry is acquired (e.g. the with-block).","Check the proxy's validity (or track singletonProxy_release) before invoking, and re-initialize on RuntimeError.","Fix thread lifecycle so release happens only after all callers are done with the proxy."],"exampleFix":"# before\nshared = multi_process_shared.MultiProcessShared(MyClass).enter()\nobj = shared.acquire()\nshared.exit()  # releases entry\nobj()  # RuntimeError: Entry was released.\n\n// after\nshared = multi_process_shared.MultiProcessShared(MyClass).enter()\nobj = shared.acquire()\ntry:\n    obj()  # safe: entry still held\nfinally:\n    shared.exit()","handlingStrategy":"try-catch","validationCode":"# acquire-and-use within the same scope; check validity before use\nshared = multi_process_shared.MultiProcessShared(MyClass).enter()\nobj = shared.acquire()\nif obj is None:\n    raise RuntimeError('shared entry not acquired')","typeGuard":"def proxy_is_valid(proxy) -> bool:\n    return getattr(proxy, '_SingletonProxy_valid', True)","tryCatchPattern":"try:\n    result = shared_obj()\nexcept RuntimeError as e:\n    if 'Entry was released.' in str(e):\n        shared_obj = reinitialize_shared()  # re-acquire the entry\n        result = shared_obj()\n    else:\n        raise","preventionTips":["Use MultiProcessShared as a context manager so acquire/release are paired","Never cache the acquired proxy beyond the release point","Coordinate threads: release only after all callers finish","Catch RuntimeError and re-acquire instead of reusing stale proxies"],"tags":["python","apache-beam","multiprocessing","shared-state","lifecycle"],"backgroundTag":"invalid-state-transition","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"}