{"record":{"id":"c8d861dc9ef84eac","repo":"github/copilot-sdk","slug":"an-in-process-ffi-runtime-library-is-already-loade","errorCode":null,"errorMessage":"An in-process FFI runtime library is already loaded from '${loadedLibraryPath}'; 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":null,"httpStatus":null,"severity":"error","filePath":"nodejs/src/ffiRuntimeHost.ts","lineNumber":52,"sourceCode":"    hostStart: KoffiFunction;\n    hostShutdown: KoffiFunction;\n    connectionOpen: KoffiFunction;\n    connectionWrite: KoffiFunction;\n    connectionClose: KoffiFunction;\n    outboundCallbackType: KoffiType;\n}\n\nlet loadedLibraryPath: string | undefined;\nlet loadedLibrary: FfiLibrary | undefined;\n\n/**\n * Loads the cdylib once per process and binds the C ABI exports. Loading a\n * different library path in the same process is unsupported.\n */\nfunction loadLibrary(libraryPath: string): FfiLibrary {\n    if (loadedLibrary) {\n        if (loadedLibraryPath !== libraryPath) {\n            throw new Error(\n                `An in-process FFI runtime library is already loaded from '${loadedLibraryPath}'; ` +\n                    `loading a different library from '${libraryPath}' in the same process is not supported.`\n            );\n        }\n        return loadedLibrary;\n    }\n\n    const lib = koffi.load(libraryPath);\n    const outboundCallbackType = koffi.pointer(\n        koffi.proto(\n            `void ${SYMBOL_PREFIX}outbound(void *userData, uint8 *bytesPtr, size_t bytesLen)`\n        )\n    );\n\n    loadedLibrary = {\n        hostStart: lib.func(`${SYMBOL_PREFIX}host_start`, \"uint32\", [\n            \"uint8*\",\n            \"size_t\",","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/nodejs/src/ffiRuntimeHost.ts#L34-L70","documentation":"The FFI runtime host loads a native cdylib once per process (module-level loadedLibrary state). If loadLibrary is asked for a path that differs from the already-loaded library path, it throws because a second copy of the same C ABI in one process is unsupported (duplicated global state, callback registration conflicts).","triggerScenarios":"Constructing a second FfiRuntimeHost in the same process with a different libraryPath than the first (e.g. pointing at another build output, version, or architecture variant of the cdylib).","commonSituations":"Test suites that switch between debug and release builds of the native library; upgrading library paths mid-process after a rebuild; multiple SDK versions of the runtime coexisting; watch-mode rebuilds changing the library file path while the process is alive.","solutions":["Use the same library path for all FfiRuntimeHost instances in a process, or reuse the existing host instance.","Restart the process when you need to load a different library build/version.","Centralize host creation (singleton) so only one path is ever requested.","Fix test/watch tooling to spawn a fresh process per library variant."],"exampleFix":"// before\nnew FfiRuntimeHost('/lib/runtime-debug.so', ...);\nnew FfiRuntimeHost('/lib/runtime-release.so', ...); // throws\n// after\nnew FfiRuntimeHost('/lib/runtime-release.so', ...); // consistent path (or reuse host)","handlingStrategy":"try-catch","validationCode":"const LIB_PATH = '/abs/path/libruntime.so'; // single shared constant\n// only ever construct with LIB_PATH","typeGuard":null,"tryCatchPattern":"let host;\ntry {\n  host = new FfiRuntimeHost(libPath, ...);\n} catch (e) {\n  if (String(e.message).includes('already loaded from')) {\n    host = getExistingHost(); // reuse the host bound to the loaded library\n  } else throw e;\n}","preventionTips":["Centralize library path in one constant/module","Use a singleton host accessor instead of constructing repeatedly","Restart the process to switch library builds","Configure test runners to use one library variant per process"],"tags":["ffi","native-library","lifecycle","process"],"backgroundTag":"conflicting-config-options","analyzedSha":"cd8cf15dc3f9e762615790aaed0a771a0f392755","analyzedAt":"2026-09-09T18:32:31.973Z","contentChangedAt":"2026-09-09T18:32:31.973Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}