Yeachan-Heo/oh-my-codex · error · Error
sendToWorkerStdin: stdin is not writable
Error message
sendToWorkerStdin: stdin is not writable
What it means
Thrown by sendToWorkerStdin when the provided stdin stream is null/undefined or its .writable property is false — i.e. the worker process's stdin pipe is closed or destroyed, so text cannot be delivered. This is a precondition failure on the stream argument, checked after trigger-text validation passes.
Source
Thrown at src/team/tmux-session.ts:3754
function assertWorkerTriggerText(text: string): void {
if (text.length >= 200) {
throw new Error('sendToWorker: text must be < 200 characters');
}
if (text.trim().length === 0) {
throw new Error('sendToWorker: text must be non-empty');
}
if (text.includes(INJECTION_MARKER)) {
throw new Error('sendToWorker: injection marker is not allowed');
}
}
export function sendToWorkerStdin(
stdin: Pick<NodeJS.WritableStream, 'write' | 'writable'> | null | undefined,
text: string,
): void {
assertWorkerTriggerText(text);
if (!stdin || !stdin.writable) {
throw new Error('sendToWorkerStdin: stdin is not writable');
}
stdin.write(`${text}\n`);
}
// Send SHORT text (<200 chars) to worker via tmux send-keys
// Validates: text < 200 chars, no injection marker
// Throws on violation
export async function sendToWorker(
sessionName: string,
workerIndex: number,
text: string,
workerPaneId?: string,
workerCli?: TeamWorkerCli,
expectedPanePid?: number,
expectedTeamOwnerId?: string,
hudPaneId?: string,
): Promise<void> {
assertWorkerTriggerText(text);View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Check worker.exitCode / worker.killed before sending; respawn the worker if it exited
- Monitor the worker's 'exit' and stdin 'close' events and stop/refresh the send path
- Guard with `if (worker.stdin?.writable)` before calling
Example fix
// before
sendToWorkerStdin(worker.stdin, text);
// after
if (worker.exitCode !== null || !worker.stdin?.writable) {
worker = await spawnWorker();
}
sendToWorkerStdin(worker.stdin, text); Defensive patterns
Strategy: type-guard
Validate before calling
if (worker.exitCode !== null) worker = await spawnWorker();
Type guard
function isStdinWritable(stdin: Pick<NodeJS.WritableStream, 'write' | 'writable'> | null | undefined): stdin is NodeJS.WritableStream { return !!stdin && stdin.writable === true; } Prevention
- Listen for worker 'exit' and stdin 'close' events to invalidate references
- Check writable right before every write
When it happens
Trigger: Calling sendToWorkerStdin(worker.stdin, text) after the worker process exited (stdin closed), passing null, or passing a stream that has been .end()ed or destroyed.
Common situations: Worker process crashed earlier and the orchestrator still holds a stale reference; race between worker exit and next send; stream explicitly closed on shutdown but send loop still running.
Related errors
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/01670b7ae8f54a8b.
Report an issue: GitHub.