{"record":{"id":"88998335b26ffaa1","repo":"github/copilot-sdk","slug":"ffiruntimehost-is-already-closed","errorCode":null,"errorMessage":"FfiRuntimeHost is already closed.","messagePattern":"FfiRuntimeHost is already closed\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"java/sdk/src/main/java/com/github/copilot/ffi/FfiRuntimeHost.java","lineNumber":100,"sourceCode":"\n    private static Path resolveLibraryPath() throws IOException {\n        return NativeRuntimeLoader.resolve();\n    }\n\n    /**\n     * Starts the in-process runtime and opens a connection.\n     *\n     * @param entrypointPath\n     *            optional explicit legacy CLI entrypoint passed in\n     *            {@code argv_json}\n     * @param options\n     *            client options used to construct {@code argv_json} and\n     *            {@code env_json}\n     */\n    public void start(String entrypointPath, CopilotClientOptions options) {\n        Objects.requireNonNull(options, \"options must not be null\");\n        if (disposed.get()) {\n            throw new IllegalStateException(\"FfiRuntimeHost is already closed.\");\n        }\n        if (serverId.get() != 0 || connectionId.get() != 0) {\n            throw new IllegalStateException(\"FfiRuntimeHost has already been started.\");\n        }\n\n        byte[] argvJson = buildArgvJson(entrypointPath, options);\n        byte[] envJson = buildEnvJson(options);\n        int hostHandle = runHostStartOnBlockingThread(argvJson, envJson);\n        if (hostHandle == 0) {\n            String lib = libraryPath != null ? libraryPath : \"<unknown>\";\n            throw new IllegalStateException(\"copilot_runtime_host_start failed (library '\" + lib + \"').\");\n        }\n\n        // Hold operationLock while publishing handles to serialize with close().\n        // Recheck disposed in case close() ran while hostStart was blocking.\n        operationLock.lock();\n        try {\n            if (disposed.get()) {","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/java/sdk/src/main/java/com/github/copilot/ffi/FfiRuntimeHost.java#L82-L118","documentation":"FfiRuntimeHost.start() throws this IllegalStateException when the host has already been disposed (disposed flag set) and cannot be started again. A closed FfiRuntimeHost is terminal; a new instance must be created to serve another in-process runtime.","triggerScenarios":"Calling start(entrypointPath, options) on an FfiRuntimeHost instance after close()/dispose completed — e.g., restarting the runtime by re-calling start on the same object instead of constructing a fresh host.","commonSituations":"Restart-after-shutdown logic that reuses the host reference; lifecycle bugs in tests or apps where close() runs in a finally and start() is later called for the next operation; DI containers caching a disposed host singleton.","solutions":["Create a new FfiRuntimeHost instance instead of calling start on a disposed one","Track host state in your application and rebuild the host after any close","Avoid closing the host for transient restarts; only close at full application shutdown","Check disposed state before start (or catch IllegalStateException) and re-create the host in the recovery path"],"exampleFix":"// before\nhost.close();\nhost.start(entrypoint, options); // IllegalState\n// after\nhost.close();\nhost = new FfiRuntimeHost(nativeBinding);\nhost.start(entrypoint, options);","handlingStrategy":"validation","validationCode":"// track disposal yourself; FfiRuntimeHost.disposed is internal\nif (hostRef.get() == null || hostClosed) {\n    hostRef.set(new FfiRuntimeHost(nativeBinding));\n}\nFfiRuntimeHost host = hostRef.get();","typeGuard":null,"tryCatchPattern":"try {\n    host.start(entrypoint, options);\n} catch (IllegalStateException e) {\n    if (String.valueOf(e.getMessage()).contains(\"already closed\")) {\n        host = new FfiRuntimeHost(nativeBinding);\n        host.start(entrypoint, options);\n    } else throw e;\n}","preventionTips":["Treat FfiRuntimeHost as single-use; create a new instance after close","Only close the host at final application shutdown","Guard restart flows to rebuild the host, not restart it","Keep host references out of long-lived singletons that outlive close"],"tags":["ffi","lifecycle","shutdown","state"],"backgroundTag":"invalid-state-transition","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"}