{"record":{"id":"b958d4f2f994efa6","repo":"paperclipai/paperclip","slug":"login-pty-routes-at-capacity","errorCode":"LOGIN_PTY_ROUTES_AT_CAPACITY","errorMessage":"LOGIN_PTY_ROUTES_AT_CAPACITY","messagePattern":"LOGIN_PTY_ROUTES_AT_CAPACITY","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"server/src/services/plugin-worker-manager.ts","lineNumber":1776,"sourceCode":"    const route: LoginPtyRoute = {\n      hostRouteId,\n      state: \"reserved\",\n      workerSessionId: null,\n      listener: null,\n      buffered: [],\n      deliveredChars: 0,\n      terminalized: false,\n      settleWait,\n      preBind: [],\n      preBindChars: 0,\n    };\n    // Reserve one process-wide aggregate route slot before any work. When the\n    // ceiling is full, reject with the fixed capacity error and open nothing,\n    // so an active login route never downgrades and the ceiling never\n    // overcommits. This never reveals the live count, the ceiling, or any\n    // other tenant.\n    if (!acquireLoginPtyRouteSlot(route)) {\n      throw new Error(LOGIN_PTY_ROUTES_AT_CAPACITY);\n    }\n    // Reserve the route by its host route identifier before the open call, so\n    // a notification that echoes this identifier can queue against it even\n    // before the worker replies.\n    loginPtyRoutesByHostRouteId.set(hostRouteId, route);\n\n    route.state = \"opening\";\n    let openResult: HostToWorkerMethods[\"loginPtyOpen\"][1];\n    try {\n      openResult = await callInternal(\n        \"loginPtyOpen\",\n        {\n          hostRouteId,\n          driverKey: input.driverKey,\n          companyId: input.companyId,\n          environmentId: input.environmentId,\n          providerLeaseId: input.providerLeaseId,\n          loginCommandKey: input.loginCommandKey,","sourceCodeStart":1758,"sourceCodeEnd":1794,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/server/src/services/plugin-worker-manager.ts#L1758-L1794","documentation":"Creating a login PTY route first reserves one process-wide aggregate route slot; if the ceiling is already full the manager throws Error('LOGIN_PTY_ROUTES_AT_CAPACITY') before opening anything, so active routes are never downgraded and capacity is never overcommitted. The error deliberately reveals no live counts or ceilings.","triggerScenarios":"Opening a new login PTY while the process-wide aggregate route limit is saturated — e.g. many users concurrently holding login PTY sessions, or leaked routes never terminalized keeping slots occupied.","commonSituations":"Long-lived login PTY sessions accumulating over server uptime; a worker crash that failed to release its route slot (leak); capacity configured too low for the tenant count; burst of simultaneous login attempts.","solutions":["Retry the login later once existing sessions close and slots free up","Check for leaked routes: worker deaths that never ran terminalizeLoginPtyRoute; restart the server process to reclaim slots","Raise the login PTY route ceiling configuration if the load is legitimate","Harden the close path so every route release path always frees its acquired slot"],"exampleFix":"// before: open unconditionally, surface raw capacity error\nconst handle = await createPluginWorkerHandle({ kind: 'login-pty', route });\n// after: pre-check/catch and degrade gracefully\ntry {\n  const handle = await createPluginWorkerHandle({ kind: 'login-pty', route });\n} catch (e) {\n  if ((e as Error).message === 'LOGIN_PTY_ROUTES_AT_CAPACITY') {\n    return respond(429, 'Login terminal sessions are at capacity; try again shortly.');\n  }\n  throw e;\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const handle = await createPluginWorkerHandle({ kind: 'login-pty', route });\n} catch (e) {\n  if ((e as Error).message === 'LOGIN_PTY_ROUTES_AT_CAPACITY') {\n    await backoffDelay(attempt); // retry with backoff; do not hot-loop\n  } else throw e;\n}","preventionTips":["Retry with exponential backoff rather than immediately reopening","Monitor route lifetimes; alert on routes that never terminalize (slot leaks)","Size the aggregate route ceiling to expected concurrent logins","Ensure all error paths in route lifecycle release acquired slots"],"tags":["capacity","pty","resource-limit"],"backgroundTag":"resource-limit-exceeded","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}