paperclipai/paperclip · error
Worker process for plugin "${pluginId}" is not writable
Error message
Worker process for plugin "${pluginId}" is not writable What it means
The JSON-RPC send path found the worker plugin's stdio channel is no longer writable (process exiting or already dead). The guard fires before attempting a write so callers learn the worker is gone rather than hitting a silent EPIPE.
Source
Thrown at server/src/services/plugin-worker-manager.ts:927
// incoming line before the JSON parse and the total streamed output for one
// execute call. A caller (a test) can lower them.
const maxIncomingMessageChars =
options.executeLogLimits?.maxIncomingMessageChars ?? MAX_WORKER_MESSAGE_CHARS;
const maxExecuteLogTotalChars =
options.executeLogLimits?.maxTotalCharsPerExecute ?? MAX_EXECUTE_LOG_TOTAL_CHARS;
// Bounds and timeouts for the login pseudo-terminal route. A caller
// (a test) can lower them to exercise the terminalize paths.
const maxLoginPtyChunkChars =
options.loginPtyLimits?.maxChunkChars ?? MAX_LOGIN_PTY_CHUNK_CHARS;
const maxLoginPtyTotalChars =
options.loginPtyLimits?.maxTotalChars ?? MAX_LOGIN_PTY_TOTAL_CHARS;
const maxLoginPtyPreBindFrames =
options.loginPtyLimits?.maxPreBindFrames ?? MAX_LOGIN_PTY_PRE_BIND_FRAMES;
const maxLoginPtyPreBindChars =
options.loginPtyLimits?.maxPreBindChars ?? MAX_LOGIN_PTY_PRE_BIND_CHARS;
const loginPtyOpenTimeoutMs =
options.loginPtyLimits?.openTimeoutMs ?? LOGIN_PTY_OPEN_TIMEOUT_MS;
const loginPtyCloseTimeoutMs =
options.loginPtyLimits?.closeTimeoutMs ?? LOGIN_PTY_CLOSE_TIMEOUT_MS;
// Bounds and timeouts for the generic duplex channel route. A caller (a test)
// can lower them to exercise each bound and the terminalize paths. Each
// "Chars" name is a historical holdover: the channel now carries `Uint8Array`
// chunks, so every one of these bounds counts raw bytes (`.length` on a
// `Uint8Array` is its byte count), not UTF-16 code units.
const maxDuplexChannelChunkChars =
options.duplexChannelLimits?.maxChunkChars ?? MAX_DUPLEX_CHANNEL_CHUNK_CHARS;
const maxDuplexChannelPreBindChars =
options.duplexChannelLimits?.maxPreBindBufferedChars ??
DUPLEX_ROUTE_INPUT_MAX_BYTES;
const maxDuplexChannelPreBindFrames =
options.duplexChannelLimits?.maxPreBindBufferedFrames ??
MAX_DUPLEX_CHANNEL_PRE_BIND_FRAMES;
// The pre-bind hold ceiling stays one frame above the buffered bound, so the
// replay, not the hold, ends the route on the buffered bound. SeeView on GitHub (pinned to 01ad858492)
Solutions
- The worker's stdin is closed (crashed or stopping). Restart the plugin worker and retry the call.
Defensive patterns
Strategy: retry
When it happens
Trigger: Thrown at server/src/services/plugin-worker-manager.ts:735 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-08-18).
Data as JSON: /api/errors/a1745a22ebdf7abe.
Report an issue: GitHub.