paperclipai/paperclip · error
LOGIN_PTY_ROUTES_AT_CAPACITY
LOGIN_PTY_ROUTES_AT_CAPACITY
Error message
LOGIN_PTY_ROUTES_AT_CAPACITY
What it means
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.
Source
Thrown at server/src/services/plugin-worker-manager.ts:1776
const route: LoginPtyRoute = {
hostRouteId,
state: "reserved",
workerSessionId: null,
listener: null,
buffered: [],
deliveredChars: 0,
terminalized: false,
settleWait,
preBind: [],
preBindChars: 0,
};
// Reserve one process-wide aggregate route slot before any work. When the
// ceiling is full, reject with the fixed capacity error and open nothing,
// so an active login route never downgrades and the ceiling never
// overcommits. This never reveals the live count, the ceiling, or any
// other tenant.
if (!acquireLoginPtyRouteSlot(route)) {
throw new Error(LOGIN_PTY_ROUTES_AT_CAPACITY);
}
// Reserve the route by its host route identifier before the open call, so
// a notification that echoes this identifier can queue against it even
// before the worker replies.
loginPtyRoutesByHostRouteId.set(hostRouteId, route);
route.state = "opening";
let openResult: HostToWorkerMethods["loginPtyOpen"][1];
try {
openResult = await callInternal(
"loginPtyOpen",
{
hostRouteId,
driverKey: input.driverKey,
companyId: input.companyId,
environmentId: input.environmentId,
providerLeaseId: input.providerLeaseId,
loginCommandKey: input.loginCommandKey,View on GitHub (pinned to 01ad858492)
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
Example fix
// before: open unconditionally, surface raw capacity error
const handle = await createPluginWorkerHandle({ kind: 'login-pty', route });
// after: pre-check/catch and degrade gracefully
try {
const handle = await createPluginWorkerHandle({ kind: 'login-pty', route });
} catch (e) {
if ((e as Error).message === 'LOGIN_PTY_ROUTES_AT_CAPACITY') {
return respond(429, 'Login terminal sessions are at capacity; try again shortly.');
}
throw e;
} Defensive patterns
Strategy: retry
Try / catch
try {
const handle = await createPluginWorkerHandle({ kind: 'login-pty', route });
} catch (e) {
if ((e as Error).message === 'LOGIN_PTY_ROUTES_AT_CAPACITY') {
await backoffDelay(attempt); // retry with backoff; do not hot-loop
} else throw e;
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- The duplex channel launch command needs at least one argumen
- Too many active setup-token login sessions.
- The bridge host reached its reserved process body byte ceili
- The bridge host reached its reserved process body byte ceili
- LOGIN_PTY_OPEN_FAILED
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/b958d4f2f994efa6.
Report an issue: GitHub.