github/copilot-sdk · error
CLI process not started
Error message
CLI process not started
What it means
connectToChildProcessViaStdio wires JSON-RPC over the spawned CLI child's stdio pipes, but the child process handle (this.cliProcess) is null. The library throws because it cannot attach stdin/stdout listeners without a started process. It indicates the connect() sequence was invoked before spawn, or the child failed to start.
Solutions
- Ensure the CLI process is started before connecting: await the start/spawn step and verify the CLI binary path resolves.
- Call connect() exactly once per client lifecycle; create a new CopilotClient instead of reconnecting after stop().
- Await each async lifecycle call — avoid firing connect() concurrently or before start() resolves.
- Check spawn configuration (env, cwd, CLI path) so process creation does not fail before the stdio hookup.
Example fix
// before
const client = new CopilotClient({ ... });
client.connect(); // not awaited, races with stop() elsewhere
// after
const client = new CopilotClient({ ... });
await client.start(); // spawn first
await client.connect(); // then connect, once Defensive patterns
Strategy: try-catch
Validate before calling
if (client.isStopped?.() || !client) {
throw new Error('Cannot connect: client lifecycle already terminated');
} Try / catch
try {
await client.start();
await client.connect();
} catch (err) {
if (err instanceof Error && err.message === 'CLI process not started') {
// recreate client and redo start()+connect() in order
}
throw err;
} Prevention
- Always await start() (spawn) before connect().
- Call connect() exactly once per client instance.
- Never reuse a client after stop(); create a new instance.
- Validate the CLI binary path exists before spawning.
When it happens
Trigger: Calling connect() (which routes to connectToChildProcessViaStdio) on a CopilotClient configured for child-process mode when the CLI process was never spawned — e.g. start/process creation failed silently, spawn was skipped, or connect() is called twice after teardown cleared cliProcess.
Common situations: Double-calling connect() without awaiting the first call, calling connect() after stop()/teardown reset internal state, or a spawn failure (bad CLI path) that left cliProcess unset while the connect step still ran.
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
- CLI child process was unexpectedly started in parent…
- Session not found
- FfiRuntimeHost is already closed.
- Runtime process not started
- CLI process not started
AI-assisted analysis of github/copilot-sdk@cd8cf15dc3 (2026-09-09).
Data as JSON: /api/errors/49f072298c63f12f.
Report an issue: GitHub.
Appendix: source
Thrown at nodejs/src/client.ts:2902
return true;
}
if (entrypoint.includes(`copilot-linux-${process.arch}`)) {
return false;
}
const report = process.report?.getReport();
const header =
report && "header" in report
? (report.header as { glibcVersionRuntime?: string })
: undefined;
return header !== undefined && header.glibcVersionRuntime === undefined;
}
/**
* Connect to child via stdio pipes
*/
private async connectToChildProcessViaStdio(): Promise<void> {
if (!this.cliProcess) {
throw new Error("CLI process not started");
}
// Keep stdin pipe errors inside the normal JSON-RPC teardown path.
// Preserve the failure reason via the gated debug log rather than discarding it.
this.cliProcess.stdin?.on("error", (err) => {
if (this.forceStopping) {
return;
}
this.state = "error";
const reason = err instanceof Error ? (err.stack ?? err.message) : String(err);
const stderrOutput = this.stderrBuffer.trim();
this.processTransportError = new Error(
`CLI server connection failed: ${reason}${stderrOutput ? `\nstderr: ${stderrOutput}` : ""}`
);
this.logDebug(`stdin pipe error: ${reason}`);
try {
this.connection?.dispose();
} catch {View on GitHub (pinned to cd8cf15dc3)