github/copilot-sdk · error · RuntimeError
The in-process runtime connection is closed.
Error message
The in-process runtime connection is closed.
What it means
_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.
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.
Example fix
# before
host.dispose()
host.send_request("ping") # raises
# after
if not host.is_disposed:
host.send_request("ping") Defensive patterns
Strategy: validation
Validate before calling
if host.is_disposed or not host.is_connected:
raise RuntimeError("restart host before sending") Type guard
def can_send(host) -> bool:
return not host.is_disposed and host.is_connected Try / catch
try:
host.send_request("ping")
except RuntimeError as e:
if "connection is closed" in str(e):
host = recreate_and_start_host() Prevention
- Track host lifecycle; never send after dispose().
- Synchronize shutdown with in-flight requests.
- Recreate host instances instead of reusing disposed ones.
When it happens
Trigger: 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.
Common situations: Calling client.request() after host.dispose(); a failed start_blocking left the connection closed but callers still send; background threads writing during shutdown.
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
- The in-process runtime connection is closed.
- An in-process FFI runtime library is already loaded from
- FfiRuntimeHost is already closed.
- FfiRuntimeHost has already been started.
- Copilot request response used after RPC connection closed.
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/bdb023f0debae040.
Report an issue: GitHub.
Appendix: source
Thrown at python/copilot/_ffi_runtime_host.py:473
everything is caught and logged.
"""
with self._callback_lock:
if self._disposed:
return
self._active_callbacks += 1
try:
if bytes_ptr and bytes_len > 0:
data = ctypes.string_at(bytes_ptr, bytes_len)
self._receive_buffer.feed(data)
except Exception: # noqa: BLE001
logger.error("In-process FFI inbound callback failed", exc_info=True)
finally:
with self._callback_lock:
self._active_callbacks -= 1
def _write_frame(self, frame: bytes) -> None:
if self._disposed or not self._connection_id:
raise RuntimeError("The in-process runtime connection is closed.")
ok = self._lib.connection_write(self._connection_id, frame, len(frame))
if not ok:
raise RuntimeError("Failed to write a frame to the in-process runtime connection.")
def dispose(self) -> None:
"""Close the FFI connection, shut down the native host, release resources.
Idempotent. Waits for any in-flight outbound callback to finish before
dropping the callback reference to avoid a use-after-free.
"""
with self._dispose_lock:
if self._disposed:
return
self._disposed = True
# Stop accepting new callbacks and wait for in-flight ones to drain.
with self._callback_lock:
pass # _disposed is set; new callbacks bail out immediately.View on GitHub (pinned to cd8cf15dc3)