{"record":{"id":"06a4adc0f3f20ec5","repo":"github/copilot-sdk","slug":"an-in-process-ffi-runtime-library-is-already-loade-06a4ad","errorCode":null,"errorMessage":"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.","messagePattern":"An in-process FFI runtime library is already loaded from '(.+?)'; loading a different library from '(.+?)' in the same process is not supported\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"dotnet/src/FfiRuntimeHost.cs","lineNumber":425,"sourceCode":"    private static HostStartDelegate? s_hostStart;\n    private static HostShutdownDelegate? s_hostShutdown;\n    private static ConnectionOpenDelegate? s_connectionOpen;\n    private static ConnectionWriteDelegate? s_connectionWrite;\n    private static ConnectionCloseDelegate? s_connectionClose;\n\n    // Held for the connection's lifetime so the marshaled function pointer handed to the\n    // native side is not collected while Rust may still invoke it.\n    private OutboundCallbackDelegate? _outboundDelegate;\n\n    private static void PrepareNativeLibrary(string libraryPath)\n    {\n        lock (NativeLock)\n        {\n            if (s_loaded)\n            {\n                if (s_loadedPath != libraryPath)\n                {\n                    throw new InvalidOperationException(\n                        $\"An in-process FFI runtime library is already loaded from '{s_loadedPath}'; \"\n                        + $\"loading a different library from '{libraryPath}' in the same process is not supported.\");\n                }\n                return;\n            }\n\n            var handle = NativeLoader.Load(libraryPath);\n            if (handle == IntPtr.Zero)\n            {\n                throw new InvalidOperationException($\"Failed to load FFI runtime library '{libraryPath}'.\");\n            }\n\n            s_hostStart = Bind<HostStartDelegate>(handle, \"copilot_runtime_host_start\");\n            s_hostShutdown = Bind<HostShutdownDelegate>(handle, \"copilot_runtime_host_shutdown\");\n            s_connectionOpen = Bind<ConnectionOpenDelegate>(handle, \"copilot_runtime_connection_open\");\n            s_connectionWrite = Bind<ConnectionWriteDelegate>(handle, \"copilot_runtime_connection_write\");\n            s_connectionClose = Bind<ConnectionCloseDelegate>(handle, \"copilot_runtime_connection_close\");\n            s_loaded = true;","sourceCodeStart":407,"sourceCodeEnd":443,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/dotnet/src/FfiRuntimeHost.cs#L407-L443","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nCreate(GetPath()); // may return different paths across calls -> throws\n// after\nprivate static readonly string RuntimePath = ResolveOnce();\nCreate(RuntimePath);\nCreate(RuntimePath);","handlingStrategy":"validation","validationCode":"if (FfiRuntimeHost.IsNativeLoaded && FfiRuntimeHost.LoadedPath != libraryPath)\n    throw new InvalidOperationException(\"Native runtime already loaded from a different path.\");","typeGuard":null,"tryCatchPattern":"try { host = FfiRuntimeHost.Create(path); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"already loaded\")) {\n    logger.LogWarning(\"Reusing existing native runtime from {Path}\", FfiRuntimeHost.LoadedPath);\n    host = existingHost;\n}","preventionTips":["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"],"tags":["ffi","native-library","process-lifetime","duplicate-load"],"backgroundTag":"module-init-failed","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}