{"record":{"id":"da2879536c62c056","repo":"github/copilot-sdk","slug":"cli-child-process-was-unexpectedly-started-in-pare","errorCode":null,"errorMessage":"CLI child process was unexpectedly started in parent process mode","messagePattern":"CLI child process was unexpectedly started in parent process mode","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"nodejs/src/client.ts","lineNumber":2941,"sourceCode":"        });\n\n        // Create JSON-RPC connection over stdin/stdout\n        this.messageWriter = new TeardownResilientStreamMessageWriter(this.cliProcess.stdin!);\n        this.connection = createMessageConnection(\n            new StreamMessageReader(this.cliProcess.stdout!),\n            this.messageWriter\n        );\n\n        this.attachConnectionHandlers();\n        this.connection.listen();\n    }\n\n    /**\n     * Connect to parent via stdio pipes\n     */\n    private async connectToParentProcessViaStdio(): Promise<void> {\n        if (this.cliProcess) {\n            throw new Error(\"CLI child process was unexpectedly started in parent process mode\");\n        }\n\n        // Create JSON-RPC connection over stdin/stdout\n        this.messageWriter = new TeardownResilientStreamMessageWriter(process.stdout);\n        this.connection = createMessageConnection(\n            new StreamMessageReader(process.stdin),\n            this.messageWriter\n        );\n\n        this.attachConnectionHandlers();\n        this.connection.listen();\n    }\n\n    /**\n     * Connect to the CLI server via TCP socket\n     */\n    private async connectViaTcp(): Promise<void> {\n        if (!this.runtimePort) {","sourceCodeStart":2923,"sourceCodeEnd":2959,"githubUrl":"https://github.com/github/copilot-sdk/blob/cd8cf15dc3f9e762615790aaed0a771a0f392755/nodejs/src/client.ts#L2923-L2959","documentation":"connectToParentProcessViaStdio is used when the library runs as a child of an editor/host and should communicate over its own stdin/stdout. In that mode a CLI child process must NOT exist; finding this.cliProcess set means the client was misconfigured or the parent-mode connect was invoked from the wrong context. The library throws to prevent corrupting the host's stdin/stdout protocol.","triggerScenarios":"Calling the parent-process-mode connect path (e.g. connectToParentProcessViaStdio, typically via a flag indicating 'we are the plugin/child') while this.cliProcess has already been spawned by start() — i.e. mixing child-process hosting with parent-process wiring on the same client instance.","commonSituations":"Embedding the client inside an editor extension where the host expects to own stdio, but the code also spawned a CLI child; calling the wrong connect variant for the configured hosting mode; reusing a client configured for one mode with the other's connect call.","solutions":["Pick one hosting mode: either spawn the CLI as a child (use the child-process connect path) or run in parent process mode — never both on the same instance.","In parent process mode, do not call start()/spawn before connecting; construct the client and immediately use the parent-mode connect.","If you previously spawned a CLI child, discard that client instance and create a fresh one for parent-process mode.","Verify the hosting-mode flag/configuration passed to CopilotClient matches the connect method being invoked."],"exampleFix":"// before\nconst client = new CopilotClient({ ... });\nawait client.start(); // spawns cliProcess\nawait client.connectToParentProcessViaStdio(); // throws\n\n// after\nconst client = new CopilotClient({ ... });\nawait client.connectToParentProcessViaStdio(); // no child spawned","handlingStrategy":"validation","validationCode":"if (hostingMode === 'parent-process') {\n  // must NOT have spawned a child\n  assert(!clientHasSpawnedChild, 'Do not call start() in parent-process mode');\n}","typeGuard":null,"tryCatchPattern":"try {\n  await client.connectToParentProcessViaStdio();\n} catch (err) {\n  if (err instanceof Error && err.message.includes('parent process mode')) {\n    client = new CopilotClient({ ...config }); // fresh instance, no spawn\n    await client.connectToParentProcessViaStdio();\n  }\n  throw err;\n}","preventionTips":["Decide the hosting mode once from configuration and route to exactly one connect path.","Never call start()/spawn before the parent-process connect.","Use a brand-new client instance when switching modes.","Keep mode selection centralized so child/parent paths cannot be mixed."],"tags":["lifecycle","stdio","mode-conflict","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"}