github/copilot-sdk · error · IllegalStateException
FfiRuntimeHost was closed during startup.
Error message
FfiRuntimeHost was closed during startup.
What it means
After the native host started, start() re-checks the disposed flag while holding operationLock. If close() ran concurrently while hostStart was blocking, the library shuts down the just-created native host (best effort) and throws, because publishing handles into a closed host would leak them.
Solutions
- Ensure close() is not invoked until after start() completes; serialize lifecycle with the same lock or a startup Future.
- Check return value / exceptions of start() before calling close() in shutdown paths.
- Orchestrate lifecycle in a single owner component.
- Catch IllegalStateException and treat as benign during shutdown.
Example fix
// before new Thread(() -> client.close()).start(); client.start(entrypoint, options); // may race // after client.start(entrypoint, options); Runtime.getRuntime().addShutdownHook(new Thread(client::close));
Defensive patterns
Strategy: try-catch
Try / catch
try { host.start(e, o); } catch (IllegalStateException ex) { if (shuttingDown.get()) { log.info("startup raced with shutdown, ignoring"); return; } throw ex; } Prevention
- Serialize lifecycle: no close() until start() returns
- Use a single owner thread/executor for init and shutdown
- Add shutdown hooks instead of ad-hoc closing threads
When it happens
Trigger: One thread calls start() while another calls close() on the same FfiRuntimeHost; close() sets disposed before start finishes its blocking native call.
Common situations: Application shutdown hook racing with initialization; a timeout-based watchdog closing the client while startup is still in flight; double-managed lifecycle (container + app both closing).
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Interrupted while starting in-process runtime host.
- FfiRuntimeHost has already been started.
- copilot_runtime_host_start failed (library '').
- copilot_runtime_connection_open failed.
- Failed to start in-process runtime host.
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/9abb92a2e69edb2e.
Report an issue: GitHub.
Appendix: source
Thrown at java/sdk/src/main/java/com/github/copilot/ffi/FfiRuntimeHost.java:124
byte[] argvJson = buildArgvJson(entrypointPath, options);
byte[] envJson = buildEnvJson(options);
int hostHandle = runHostStartOnBlockingThread(argvJson, envJson);
if (hostHandle == 0) {
String lib = libraryPath != null ? libraryPath : "<unknown>";
throw new IllegalStateException("copilot_runtime_host_start failed (library '" + lib + "').");
}
// Hold operationLock while publishing handles to serialize with close().
// Recheck disposed in case close() ran while hostStart was blocking.
operationLock.lock();
try {
if (disposed.get()) {
try {
nativeBinding.hostShutdown(hostHandle);
} catch (Throwable ignored) {
// Best effort
}
throw new IllegalStateException("FfiRuntimeHost was closed during startup.");
}
serverId.set(hostHandle);
OutboundCallback callback = createOutboundCallback();
callbackRef = callback;
int connHandle = nativeBinding.connectionOpen(hostHandle, callback, Pointer.NULL, null, 0, null, 0, null,
0);
if (connHandle == 0) {
try {
nativeBinding.hostShutdown(hostHandle);
} catch (Throwable ignored) {
// Best effort
}
serverId.set(0);
callbackRef = null;
throw new IllegalStateException("copilot_runtime_connection_open failed.");
}
connectionId.set(connHandle);View on GitHub (pinned to cd8cf15dc3)