can1357/oh-my-pi · error · Error

${this.#options.languageName} kernel stdin is not open

Error message

${this.#options.languageName} kernel stdin is not open

What it means

`#writeLine` writes newline-delimited IPC messages to the kernel's stdin stream. When `#stdin` is null — kernel not started, stdin already closed on shutdown, or the process died and streams were torn down — it throws `"<language> kernel stdin is not open"`. Both `execute` (sending code) and `shutdown` (sending the exit command) go through this path.

Source

Thrown at packages/coding-agent/src/eval/kernel-base.ts:423

		for (const entry of pending) {
			if (entry.settled) continue;
			entry.settled = true;
			void entry.options?.onChunk?.(`[kernel] ${reason}\n`);
			entry.resolve({
				status: "error",
				cancelled: true,
				timedOut: entry.timedOut,
				stdinRequested: entry.stdinRequested,
				executionCount: entry.executionCount,
				error: entry.error,
				kernelKilled: entry.kernelKilled || kernelKilledDefault,
			});
		}
	}

	async #writeLine(line: string): Promise<void> {
		if (!this.#stdin) {
			throw new Error(`${this.#options.languageName} kernel stdin is not open`);
		}
		if (this.#options.traceIpc) {
			logger.debug(`${this.#options.languageName}Kernel send`, { preview: line.slice(0, 120) });
		}
		this.#stdin.write(`${line}\n`);
		this.#stdin.flush();
	}

	#startReader(stream: ReadableStream<Uint8Array>): void {
		const reader = stream.getReader();
		const decoder = new TextDecoder();
		const loop = async () => {
			try {
				while (true) {
					const { done, value } = await reader.read();
					if (done) break;
					this.#readBuffer += decoder.decode(value, { stream: true });
					await this.#flushFrames();

View on GitHub (pinned to 9690622007)

Solutions

  1. Ensure `start()` completed successfully before executing; check `isAlive()` first
  2. Make shutdown idempotent in caller code — skip or try-catch shutdown when the kernel already exited
  3. Restart the kernel (recreate the session) if the process died and stdin closed

Example fix

// before
await kernel.shutdown(); // may throw if already dead
// after
if (kernel.isAlive()) {
  await kernel.shutdown().catch(() => undefined);
}
Defensive patterns

Strategy: try-catch

Validate before calling

if (!kernel.isAlive()) {
  throw new Error("skip write: kernel stdin closed"); // or restart first
}

Try / catch

try {
  await kernel.shutdown();
} catch (err) {
  if (err instanceof Error && /stdin is not open/.test(err.message)) {
    // kernel already gone; treat shutdown as done
  }
}

Prevention

When it happens

Trigger: Calling `execute` on a kernel whose stdin stream closed (process exited) or was never opened; calling `shutdown` after the kernel process already terminated and its stdin was released.

Common situations: Kernel process crashed mid-session so subsequent execute calls hit a closed stdin; double-shutdown (shutdown called twice, second call finds stdin null); executing before `start()` finished opening the streams.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/8f18b73adb32bbdd. Report an issue: GitHub.