{"record":{"id":"bdb023f0debae040","repo":"github/copilot-sdk","slug":"the-in-process-runtime-connection-is-closed-bdb023","errorCode":null,"errorMessage":"The in-process runtime connection is closed.","messagePattern":"The in-process runtime connection is closed\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"python/copilot/_ffi_runtime_host.py","lineNumber":473,"sourceCode":"        everything is caught and logged.\n        \"\"\"\n        with self._callback_lock:\n            if self._disposed:\n                return\n            self._active_callbacks += 1\n        try:\n            if bytes_ptr and bytes_len > 0:\n                data = ctypes.string_at(bytes_ptr, bytes_len)\n                self._receive_buffer.feed(data)\n        except Exception:  # noqa: BLE001\n            logger.error(\"In-process FFI inbound callback failed\", exc_info=True)\n        finally:\n            with self._callback_lock:\n                self._active_callbacks -= 1\n\n    def _write_frame(self, frame: bytes) -> None:\n        if self._disposed or not self._connection_id:\n            raise RuntimeError(\"The in-process runtime connection is closed.\")\n        ok = self._lib.connection_write(self._connection_id, frame, len(frame))\n        if not ok:\n            raise RuntimeError(\"Failed to write a frame to the in-process runtime connection.\")\n\n    def dispose(self) -> None:\n        \"\"\"Close the FFI connection, shut down the native host, release resources.\n\n        Idempotent. Waits for any in-flight outbound callback to finish before\n        dropping the callback reference to avoid a use-after-free.\n        \"\"\"\n        with self._dispose_lock:\n            if self._disposed:\n                return\n            self._disposed = True\n\n        # Stop accepting new callbacks and wait for in-flight ones to drain.\n        with self._callback_lock:\n            pass  # _disposed is set; new callbacks bail out immediately.","sourceCodeStart":455,"sourceCodeEnd":491,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/python/copilot/_ffi_runtime_host.py#L455-L491","documentation":"_write_frame refuses to write when the host is disposed or the connection id is zero, meaning the in-process runtime connection is no longer open. Any send attempt after dispose or a failed connection open hits this error.","triggerScenarios":"Sending a request/notification on FfiRuntimeHost after dispose() was called, or before/after the connection was successfully opened (connection id 0), including queued writes racing with disposal.","commonSituations":"Calling client.request() after host.dispose(); a failed start_blocking left the connection closed but callers still send; background threads writing during shutdown.","solutions":["Ensure start_blocking completed successfully and the host is not disposed before sending frames.","Guard send paths with a lifecycle check (disposed/connection open) before writing.","Re-create the host and restart the connection if it was already disposed.","Synchronize shutdown so no writer threads still hold references during dispose."],"exampleFix":"# before\nhost.dispose()\nhost.send_request(\"ping\")  # raises\n# after\nif not host.is_disposed:\n    host.send_request(\"ping\")","handlingStrategy":"validation","validationCode":"if host.is_disposed or not host.is_connected:\n    raise RuntimeError(\"restart host before sending\")","typeGuard":"def can_send(host) -> bool:\n    return not host.is_disposed and host.is_connected","tryCatchPattern":"try:\n    host.send_request(\"ping\")\nexcept RuntimeError as e:\n    if \"connection is closed\" in str(e):\n        host = recreate_and_start_host()","preventionTips":["Track host lifecycle; never send after dispose().","Synchronize shutdown with in-flight requests.","Recreate host instances instead of reusing disposed ones."],"tags":["ffi","connection-closed","lifecycle"],"backgroundTag":"invalid-state-transition","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}