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_resolvedLibraryPath}'; loading a different library from '{libraryPath}' in the same process is not supported. What it means
PrepareNativeLibrary enforces that only one FFI runtime library path can ever be resolved per process (guarded by ResolverLock). If a first Create registered s_resolvedLibraryPath and a later call passes a different libraryPath, the check throws InvalidOperationException — two distinct in-process runtimes in one process are unsupported.
Solutions
- Use a single, consistent library path for all FfiRuntimeHost instances in the process.
- Dispose all hosts and restart the process if a different runtime binary is genuinely needed.
- In tests, run each library-path variant in a separate test process/assembly.
- Ensure config or environment resolving the library path is stable across the process lifetime.
Example fix
// before Create(@"C:\runtimes\debug\copilot_runtime.dll"); Create(@"C:\runtimes\release\copilot_runtime.dll"); // throws // after var path = @"C:\runtimes\debug\copilot_runtime.dll"; Create(path); Create(path); // same path is fine
Defensive patterns
Strategy: validation
Validate before calling
if (FfiRuntimeHost.CurrentResolvedLibraryPath is { } p && p != libraryPath)
throw new InvalidOperationException($"Process already uses runtime '{p}'; refusing '{libraryPath}'."); Try / catch
try { host = FfiRuntimeHost.Create(libraryPath); }
catch (InvalidOperationException ex) when (ex.Message.Contains("already loaded")) {
host = existingHost; // reuse the previously created host
} Prevention
- Resolve the library path once per process and cache it
- Never vary the runtime path via mutable config at runtime
- Isolate library-path variants in separate test processes
- Reuse a single FfiRuntimeHost instance
When it happens
Trigger: Calling Create twice with different library paths (e.g. different build outputs, architectures, or copied binaries of the runtime) within the same process lifetime.
Common situations: Tests that point at Debug and Release builds of the native lib in one xUnit process; app reconfiguration changing the runtime path after the first host was created; hot-swapping a rebuilt native DLL.
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/94f529a2652d6513.
Report an issue: GitHub.
Appendix: source
Thrown at dotnet/src/FfiRuntimeHost.cs:271
private static string? s_resolvedLibraryPath;
// A normal (non-pinned) handle to this instance, passed to the native side as
// the callback's user_data so the static outbound callback can route back here.
private GCHandle _selfHandle;
/// <summary>
/// Registers (once) a process-wide <see cref="NativeLibrary.SetDllImportResolver"/>
/// that maps <see cref="LibraryName"/> to the absolute <c>runtime.node</c> path so the
/// <see cref="LibraryImportAttribute"/> stubs resolve. The resolved handle is cached by
/// the runtime after first use, so all in-process hosts share a single loaded library.
/// </summary>
private static void PrepareNativeLibrary(string libraryPath)
{
lock (ResolverLock)
{
if (s_resolvedLibraryPath is not null && s_resolvedLibraryPath != libraryPath)
{
throw new InvalidOperationException(
$"An in-process FFI runtime library is already loaded from '{s_resolvedLibraryPath}'; "
+ $"loading a different library from '{libraryPath}' in the same process is not supported.");
}
s_resolvedLibraryPath = libraryPath;
if (!s_resolverRegistered)
{
NativeLibrary.SetDllImportResolver(typeof(FfiRuntimeHost).Assembly, Resolve);
s_resolverRegistered = true;
}
}
}
private static IntPtr Resolve(string libraryName, Assembly assembly, DllImportSearchPath? searchPath)
{
if (libraryName == LibraryName && s_resolvedLibraryPath is not null)
{
return NativeLibrary.Load(s_resolvedLibraryPath);
}View on GitHub (pinned to cd8cf15dc3)