github/copilot-sdk · error · InvalidOperationException
An in-process FFI runtime library is already loaded from
Error message
An in-process FFI runtime library is already loaded from '{s_loadedPath}'; loading a different library from '{libraryPath}' in the same process is not supported. What it means
Once the native library has actually been loaded (s_loaded), PrepareNativeLibrary rejects any later call with a different path under NativeLock, mirroring the resolver-level check. Loading a second, different native runtime in the same process is unsupported and throws InvalidOperationException.
Solutions
- Standardize on one runtime library path per process.
- Restart the process to switch native runtime binaries.
- Unify test suites so all fixtures use the same library path (or run in isolated processes).
- Fix path-resolution logic (env var, config) so it cannot yield different values over time.
Example fix
// before Create(GetPath()); // may return different paths across calls -> throws // after private static readonly string RuntimePath = ResolveOnce(); Create(RuntimePath); Create(RuntimePath);
Defensive patterns
Strategy: validation
Validate before calling
if (FfiRuntimeHost.IsNativeLoaded && FfiRuntimeHost.LoadedPath != libraryPath)
throw new InvalidOperationException("Native runtime already loaded from a different path."); Try / catch
try { host = FfiRuntimeHost.Create(path); }
catch (InvalidOperationException ex) when (ex.Message.Contains("already loaded")) {
logger.LogWarning("Reusing existing native runtime from {Path}", FfiRuntimeHost.LoadedPath);
host = existingHost;
} Prevention
- Single source of truth for the native library path
- Avoid path-resolution logic that can change between calls
- Run multi-config test suites in isolated processes
- Create the host once at startup and share it
When it happens
Trigger: Create called with a different libraryPath after a successful native load — e.g. reconfiguring the runtime path, or mixing runtime variants in one test run or plugin host.
Common situations: Same as the resolver-path variant: mixed Debug/Release natives in a shared test process, config-driven path change mid-run, architecture-mismatched copies of the library.
Related errors
- An in-process FFI runtime library is already loaded from
- An in-process FFI runtime library is already loaded from
- FFI runtime library not found at
- copilot_runtime_host_start failed
- copilot_runtime_connection_open failed.
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/06a4adc0f3f20ec5.
Report an issue: GitHub.
Appendix: source
Thrown at dotnet/src/FfiRuntimeHost.cs:425
private static HostStartDelegate? s_hostStart;
private static HostShutdownDelegate? s_hostShutdown;
private static ConnectionOpenDelegate? s_connectionOpen;
private static ConnectionWriteDelegate? s_connectionWrite;
private static ConnectionCloseDelegate? s_connectionClose;
// Held for the connection's lifetime so the marshaled function pointer handed to the
// native side is not collected while Rust may still invoke it.
private OutboundCallbackDelegate? _outboundDelegate;
private static void PrepareNativeLibrary(string libraryPath)
{
lock (NativeLock)
{
if (s_loaded)
{
if (s_loadedPath != libraryPath)
{
throw new InvalidOperationException(
$"An in-process FFI runtime library is already loaded from '{s_loadedPath}'; "
+ $"loading a different library from '{libraryPath}' in the same process is not supported.");
}
return;
}
var handle = NativeLoader.Load(libraryPath);
if (handle == IntPtr.Zero)
{
throw new InvalidOperationException($"Failed to load FFI runtime library '{libraryPath}'.");
}
s_hostStart = Bind<HostStartDelegate>(handle, "copilot_runtime_host_start");
s_hostShutdown = Bind<HostShutdownDelegate>(handle, "copilot_runtime_host_shutdown");
s_connectionOpen = Bind<ConnectionOpenDelegate>(handle, "copilot_runtime_connection_open");
s_connectionWrite = Bind<ConnectionWriteDelegate>(handle, "copilot_runtime_connection_write");
s_connectionClose = Bind<ConnectionCloseDelegate>(handle, "copilot_runtime_connection_close");
s_loaded = true;View on GitHub (pinned to cd8cf15dc3)