{"record":{"id":"9d878b5302c489f5","repo":"github/copilot-sdk","slug":"an-in-process-ffi-runtime-library-is-already-loade-9d878b","errorCode":null,"errorMessage":"An in-process FFI runtime library is already loaded from ''; loading a different library from '' 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":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"java/sdk/src/main/java/com/github/copilot/ffi/JnaNativeBinding.java","lineNumber":207,"sourceCode":"     *            absolute path to the {@code runtime.node} native library\n     * @throws IllegalStateException\n     *             if a <em>different</em> library path has already been loaded in\n     *             this JVM process\n     */\n    JnaNativeBinding(Path libraryPath) {\n        Path absPath = libraryPath.toAbsolutePath().normalize();\n        synchronized (LOAD_LOCK) {\n            if (loadedLib == null) {\n                LOG.fine(() -> \"Loading native library from: \" + absPath);\n                try {\n                    loadedLib = Native.load(absPath.toString(), CopilotRuntimeLibrary.class);\n                } catch (UnsatisfiedLinkError e) {\n                    throw new IllegalStateException(\"Failed to load native library from '\" + absPath + \"'\", e);\n                }\n                loadedPath = absPath;\n                LOG.fine(() -> \"Native library loaded: \" + absPath);\n            } else if (!absPath.equals(loadedPath)) {\n                throw new IllegalStateException(\"An in-process FFI runtime library is already loaded from '\"\n                        + loadedPath + \"'; loading a different library from '\" + absPath\n                        + \"' in the same process is not supported.\");\n            }\n        }\n        this.lib = loadedLib;\n    }\n\n    /**\n     * Testing constructor — accepts a pre-built {@link CopilotRuntimeLibrary}\n     * directly, bypassing disk I/O and the static singleton guard.\n     *\n     * <p>\n     * This constructor is package-private and intended solely for unit tests.\n     *\n     * @param library\n     *            a {@link CopilotRuntimeLibrary} stub or mock for testing\n     */\n    JnaNativeBinding(CopilotRuntimeLibrary library) {","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/java/sdk/src/main/java/com/github/copilot/ffi/JnaNativeBinding.java#L189-L225","documentation":"The class keeps a static loadedLib/loadedPath pair: only one native runtime library can be loaded per JVM process. Constructing a JnaNativeBinding with a different absolute path while a library is already loaded throws, because unloading JNA libraries is not possible and mixing runtimes would corrupt native state.","triggerScenarios":"Creating a second FfiRuntimeHost/JnaNativeBinding pointing at a different library path (e.g. after a runtime upgrade, or tests using different extracted copies) within the same JVM.","commonSituations":"Test suites where one test pins an old runtime path and another uses a new one; hot-redeploy in a shared JVM; a config change altering the runtime directory between inits.","solutions":["Reuse a single library path for the whole process (same cached runtime file).","Reuse the existing JnaNativeBinding/FfiRuntimeHost instead of constructing a new one.","Run tests needing different runtimes in separate JVMs (e.g. per-test fork).","Restore the original runtime path configuration that was used on first load."],"exampleFix":"// before\nnew JnaNativeBinding(\"/cache/runtime-v1/lib.so\");\nnew JnaNativeBinding(\"/cache/runtime-v2/lib.so\"); // throws\n// after\nNativeBindingHolder.getOrCreate(\"/cache/runtime-v2/lib.so\"); // cached singleton per JVM","handlingStrategy":"type-guard","validationCode":"if (NativeRuntimeRegistry.loadedPath != null && !NativeRuntimeRegistry.loadedPath.equals(requestedPath)) throw new IllegalStateException(\"different runtime already loaded\");","typeGuard":"boolean canLoad(Path p) { return loadedPath == null || loadedPath.equals(p.toAbsolutePath().normalize()); }","tryCatchPattern":"try { binding = new JnaNativeBinding(path); } catch (IllegalStateException ex) { if (ex.getMessage().contains(\"already loaded\")) { binding = existingSingleton; } else throw ex; }","preventionTips":["Access JnaNativeBinding through a process-wide singleton/factory","Pin one runtime version per JVM","Fork separate JVMs for tests needing different runtimes"],"tags":["java","jna","native","singleton"],"backgroundTag":"unsupported-operation","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"}