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

  1. Retry the login later once existing sessions close and slots free up
  2. Check for leaked routes: worker deaths that never ran terminalizeLoginPtyRoute; restart the server process to reclaim slots
  3. Raise the login PTY route ceiling configuration if the load is legitimate
  4. 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

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


AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10). Data as JSON: /api/errors/b958d4f2f994efa6. Report an issue: GitHub.