{"record":{"id":"7dec67c6e07cb3c1","repo":"github/copilot-sdk","slug":"ffiruntimehost-has-already-been-started","errorCode":null,"errorMessage":"FfiRuntimeHost has already been started.","messagePattern":"FfiRuntimeHost has already been started\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"java/sdk/src/main/java/com/github/copilot/ffi/FfiRuntimeHost.java","lineNumber":103,"sourceCode":"    }\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()) {\n                try {\n                    nativeBinding.hostShutdown(hostHandle);\n                } catch (Throwable ignored) {","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/java/sdk/src/main/java/com/github/copilot/ffi/FfiRuntimeHost.java#L85-L121","documentation":"FfiRuntimeHost.start() enforces single-start semantics: if the host handle (serverId) or connection handle (connectionId) is already non-zero, the host has been started previously and a second start would leak native resources. The library throws IllegalStateException immediately without touching native code.","triggerScenarios":"Calling start(entrypointPath, options) twice on the same FfiRuntimeHost instance without close() in between; e.g. openInProcessTransport re-invoking start after a prior successful start, or application retry logic calling start again after it already succeeded.","commonSituations":"Framework code that creates the client on multiple lifecycle events (servlet init + first request), a retry wrapper that re-calls start after an unrelated error, or accidental shared singleton host reused by two components each calling start().","solutions":["Call start() only once per FfiRuntimeHost instance; guard with an isStarted()/state check before calling.","If restart is needed, call close() first and create a new FfiRuntimeHost instance.","Refactor to lazy initialization so only one code path invokes start()."],"exampleFix":"// before\nhost.start(entrypoint, options);\nhost.start(entrypoint, options); // throws\n// after\nif (!hostStarted) {\n    host.start(entrypoint, options);\n    hostStarted = true;\n}","handlingStrategy":"type-guard","validationCode":"if (hostStarted.get()) { throw new IllegalStateException(\"already started\"); }\nhost.start(entrypoint, options); hostStarted.set(true);","typeGuard":"boolean isStarted(FfiRuntimeHost h) { return h != null && h.getState() != FfiRuntimeHost.State.NEW; }","tryCatchPattern":"try { host.start(e, o); } catch (IllegalStateException ex) { if (!ex.getMessage().contains(\"already been started\")) throw ex; }","preventionTips":["Initialize the host in exactly one lifecycle method","Use an AtomicBoolean/enum state machine around start()","Never call start() from retry logic without recreating the host"],"tags":["java","ffi","lifecycle","illegal-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"}