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. See

View on GitHub (pinned to 01ad858492)

Solutions

  1. 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.