github/copilot-sdk · error · RuntimeError

An in-process FFI runtime library is already loaded from

Error message

An in-process FFI runtime library is already loaded from '{_loaded_library_path}'; loading a different library from '{library_path}' in the same process is not supported.

What it means

_load_library enforces one FFI runtime library per process: once a native runtime is loaded, loading a library from a different path is rejected because the process cannot safely host two runtimes. Loading the same path again returns the cached handle.

Solutions

  1. Use a single FfiRuntimeHost per process, or reuse the existing one instead of creating a new host with a different library path.
  2. Ensure all hosts resolve to the exact same absolute runtime library path (same version/install location).
  3. If you must switch runtimes, do it in a separate subprocess.
  4. Dispose the old host and reload only if the library truly matches the previously loaded path.
Defensive patterns

Strategy: validation

Validate before calling

from copilot import _ffi_runtime_host as h
if h._loaded_library is not None and h._loaded_library_path != str(Path(library_path).resolve()):
    raise RuntimeError("different FFI runtime already loaded; reuse existing host")

Try / catch

try:
    host = FfiRuntimeHost.create(library_path)
except RuntimeError as e:
    if "already loaded" in str(e):
        host = get_existing_host()

Prevention

When it happens

Trigger: Constructing FfiRuntimeHost (via __init__/create) twice in one process with different resolved library_path values — e.g. one instance from a cached CLI path and another from a custom/in-process runtime path.

Common situations: Mixing a downloaded CLI runtime with a bundled in-process runtime in tests; two library versions resolving to different absolute paths; pytest fixtures creating hosts with different paths.

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


AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09). Data as JSON: /api/errors/71fef8c5e6fc0580. Report an issue: GitHub.

Appendix: source

Thrown at python/copilot/_ffi_runtime_host.py:206

        self.connection_write = getattr(lib, f"{_SYMBOL_PREFIX}connection_write")
        self.connection_write.argtypes = [
            ctypes.c_uint32,
            ctypes.c_char_p,
            ctypes.c_size_t,
        ]
        self.connection_write.restype = ctypes.c_bool

        self.connection_close = getattr(lib, f"{_SYMBOL_PREFIX}connection_close")
        self.connection_close.argtypes = [ctypes.c_uint32]
        self.connection_close.restype = ctypes.c_bool


def _load_library(library_path: str) -> _FfiLibrary:
    global _loaded_library, _loaded_library_path
    with _load_lock:
        if _loaded_library is not None:
            if _loaded_library_path != library_path:
                raise RuntimeError(
                    f"An in-process FFI runtime library is already loaded from "
                    f"'{_loaded_library_path}'; loading a different library from "
                    f"'{library_path}' in the same process is not supported."
                )
            return _FfiLibrary(_loaded_library)

        # Load with immediate binding (RTLD_NOW) on POSIX, matching the .NET/Rust
        # hosts. The runtime cdylib from the platform release package is self-contained;
        # eager binding surfaces any load problem here rather than at first call.
        if sys.platform == "win32":
            lib = ctypes.WinDLL(library_path)
        else:
            lib = ctypes.CDLL(library_path, mode=os.RTLD_NOW | os.RTLD_LOCAL)
        _loaded_library = lib
        _loaded_library_path = library_path
        return _FfiLibrary(lib)

View on GitHub (pinned to cd8cf15dc3)