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
- Ensure `start()` completed successfully before executing; check `isAlive()` first
- Make shutdown idempotent in caller code — skip or try-catch shutdown when the kernel already exited
- 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
- Make shutdown idempotent in calling code (catch this error)
- Don't execute on a kernel whose process exited — check isAlive() first
- Track process exit so you never double-shutdown
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
- Overlapping replacements detected; refine pattern to avoid a
- ${this.#options.languageName} kernel is not running
- lsp mux smoke failed: no ping response (${proc.peekStderr().
- Computed edit range is out of bounds
- {} terminated abnormally
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/8f18b73adb32bbdd.
Report an issue: GitHub.