{"record":{"id":"a1745a22ebdf7abe","repo":"paperclipai/paperclip","slug":"worker-process-for-plugin-pluginid-is-not-wri","errorCode":null,"errorMessage":"Worker process for plugin \"${pluginId}\" is not writable","messagePattern":"Worker process for plugin \"(.+?)\" is not writable","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/plugin-worker-manager.ts","lineNumber":927,"sourceCode":"  // incoming line before the JSON parse and the total streamed output for one\n  // execute call. A caller (a test) can lower them.\n  const maxIncomingMessageChars =\n    options.executeLogLimits?.maxIncomingMessageChars ?? MAX_WORKER_MESSAGE_CHARS;\n  const maxExecuteLogTotalChars =\n    options.executeLogLimits?.maxTotalCharsPerExecute ?? MAX_EXECUTE_LOG_TOTAL_CHARS;\n\n  // Bounds and timeouts for the login pseudo-terminal route. A caller\n  // (a test) can lower them to exercise the terminalize paths.\n  const maxLoginPtyChunkChars =\n    options.loginPtyLimits?.maxChunkChars ?? MAX_LOGIN_PTY_CHUNK_CHARS;\n  const maxLoginPtyTotalChars =\n    options.loginPtyLimits?.maxTotalChars ?? MAX_LOGIN_PTY_TOTAL_CHARS;\n  const maxLoginPtyPreBindFrames =\n    options.loginPtyLimits?.maxPreBindFrames ?? MAX_LOGIN_PTY_PRE_BIND_FRAMES;\n  const maxLoginPtyPreBindChars =\n    options.loginPtyLimits?.maxPreBindChars ?? MAX_LOGIN_PTY_PRE_BIND_CHARS;\n  const loginPtyOpenTimeoutMs =\n    options.loginPtyLimits?.openTimeoutMs ?? LOGIN_PTY_OPEN_TIMEOUT_MS;\n  const loginPtyCloseTimeoutMs =\n    options.loginPtyLimits?.closeTimeoutMs ?? LOGIN_PTY_CLOSE_TIMEOUT_MS;\n\n  // Bounds and timeouts for the generic duplex channel route. A caller (a test)\n  // can lower them to exercise each bound and the terminalize paths. Each\n  // \"Chars\" name is a historical holdover: the channel now carries `Uint8Array`\n  // chunks, so every one of these bounds counts raw bytes (`.length` on a\n  // `Uint8Array` is its byte count), not UTF-16 code units.\n  const maxDuplexChannelChunkChars =\n    options.duplexChannelLimits?.maxChunkChars ?? MAX_DUPLEX_CHANNEL_CHUNK_CHARS;\n  const maxDuplexChannelPreBindChars =\n    options.duplexChannelLimits?.maxPreBindBufferedChars ??\n    DUPLEX_ROUTE_INPUT_MAX_BYTES;\n  const maxDuplexChannelPreBindFrames =\n    options.duplexChannelLimits?.maxPreBindBufferedFrames ??\n    MAX_DUPLEX_CHANNEL_PRE_BIND_FRAMES;\n  // The pre-bind hold ceiling stays one frame above the buffered bound, so the\n  // replay, not the hold, ends the route on the buffered bound. See","sourceCodeStart":909,"sourceCodeEnd":945,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/plugin-worker-manager.ts#L909-L945","documentation":"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.","triggerScenarios":"Thrown at server/src/services/plugin-worker-manager.ts:735 when the library encounters an invalid state.","commonSituations":"See trigger scenarios.","solutions":["The worker's stdin is closed (crashed or stopping). Restart the plugin worker and retry the call."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-08-18T22:49:45.177Z","contentChangedAt":"2026-08-18T22:49:45.177Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}