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

  1. Standardize on one runtime library path per process.
  2. Restart the process to switch native runtime binaries.
  3. Unify test suites so all fixtures use the same library path (or run in isolated processes).
  4. 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

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


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)