{"record":{"id":"490a8cbf160d5d9e","repo":"apache/beam","slug":"asynchronous-computation-was-cancelled","errorCode":null,"errorMessage":"Asynchronous computation was cancelled.","messagePattern":"Asynchronous computation was cancelled\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"sdks/python/apache_beam/runners/interactive/recording_manager.py","lineNumber":161,"sourceCode":"\n  def result(self, timeout=None):\n    return self._future.result(timeout=timeout)\n\n  def done(self):\n    return self._future.done()\n\n  def exception(self, timeout=None):\n    try:\n      return self._future.exception(timeout=timeout)\n    except TimeoutError:\n      return None\n\n  def wait_for_completion(self, timeout=None):\n    if not self._completed_event.wait(timeout=timeout):\n      raise TimeoutError(\n          'Timeout waiting for asynchronous computation completion.')\n    if self._future.cancelled():\n      raise RuntimeError('Asynchronous computation was cancelled.')\n    exc = self.exception()\n    if exc:\n      raise exc\n\n  def _on_done(self, future: Future):\n    try:\n      if future.cancelled():\n        self.update_display('Computation Cancelled.', 1.0)\n        return\n\n      exc = future.exception()\n      if exc:\n        self.update_display(f'Error: {exc}', 1.0)\n        _LOGGER.error('Asynchronous computation failed: %s', exc, exc_info=exc)\n      else:\n        self.update_display('Computation Finished Successfully.', 1.0)\n        res = future.result()\n        if res and res.state == PipelineState.DONE:","sourceCodeStart":143,"sourceCodeEnd":179,"githubUrl":"https://github.com/apache/beam/blob/12126d8942aaf848030c478b4c6a28c6af861c66/sdks/python/apache_beam/runners/interactive/recording_manager.py#L143-L179","documentation":"After the completed event fires, wait_for_completion checks whether the underlying Future was cancelled; if so it raises RuntimeError('Asynchronous computation was cancelled.'). This signals the recording's background computation was aborted rather than completed or failed with an exception.","triggerScenarios":"Calling Recording.cancel() on an active recording and then calling wait_for_completion; the recording manager cancelling a computation (e.g. a superseded or timed-out async compute) before the future resolved.","commonSituations":"Notebook code that cancels a recording on interrupt/timeout and later tries to read results from the same Recording object.","solutions":["Do not call wait_for_completion on a recording you have cancelled; create a new recording instead","Treat RuntimeError as 'computation aborted' and re-trigger the computation (ib.collect or record again)","Check recording state via the manager before waiting","Avoid cancelling recordings mid-flight unless you also discard them"],"exampleFix":"// before\nrecording.cancel()\nrecording.wait_for_completion()\n// after\nrecording.cancel()\nrecording = ib.recordings.record(pcolls, max_n=100)  # start a fresh recording\nrecording.wait_for_completion()","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"def is_cancelled(rec):\n    return rec._future is not None and rec._future.cancelled()","tryCatchPattern":"try:\n    recording.wait_for_completion()\nexcept RuntimeError as e:\n    if 'cancelled' in str(e):\n        recording = ib.recordings.record(pcolls, max_n=100)  # restart","preventionTips":["Never wait on a Recording after calling cancel() on it","Discard cancelled recordings immediately","Avoid external code paths that cancel futures of active recordings","Track recording lifecycle states in notebook tooling"],"tags":["async","cancelled","interactive-beam"],"backgroundTag":"operation-cancelled","analyzedSha":"12126d8942aaf848030c478b4c6a28c6af861c66","analyzedAt":"2026-09-13T01:50:10.254Z","contentChangedAt":"2026-09-13T01:50:10.254Z","schemaVersion":2},"datasetVersion":"2026-09-20T03:17:13.778Z"}