paperclipai/paperclip · error
LOGIN_PTY_OPEN_FAILED
LOGIN_PTY_OPEN_FAILED
Error message
LOGIN_PTY_OPEN_FAILED
What it means
After requesting a login PTY open, the manager derives a bindable worker session id from the reply. If the reply is malformed or the route already left the `opening` state (a late/duplicate open reply), the route is terminalized and Error('LOGIN_PTY_OPEN_FAILED') is thrown — a late or duplicate reply never binds, revives, or reopens a route.
Source
Thrown at server/src/services/plugin-worker-manager.ts:1811
providerLeaseId: input.providerLeaseId,
loginCommandKey: input.loginCommandKey,
sessionHome: input.sessionHome,
},
loginPtyOpenTimeoutMs,
);
} catch (err) {
// A send failure, an RPC rejection, or an open timeout. Terminalize the
// route exactly once and fail closed.
await terminalizeLoginPtyRoute(route);
throw err instanceof Error ? err : new Error(LOGIN_PTY_OPEN_FAILED);
}
const workerSessionId = readBindableWorkerSessionId(route, openResult);
if (!workerSessionId) {
// A malformed reply, or a route that already left `opening`. A late or a
// duplicate reply never binds, revives, or reopens a route.
await terminalizeLoginPtyRoute(route);
throw new Error(LOGIN_PTY_OPEN_FAILED);
}
if (loginPtyRoutesByWorkerSessionId.has(workerSessionId)) {
// A live route already owns this worker session identifier. Fail closed
// instead of binding a second route to it.
await terminalizeLoginPtyRoute(route);
throw new Error(LOGIN_PTY_OPEN_FAILED);
}
// Bind the worker session identifier one time and move the route to `open`.
route.workerSessionId = workerSessionId;
route.state = "open";
loginPtyRoutesByWorkerSessionId.set(workerSessionId, route);
// Replay every record the route queued before the bind, in arrival order.
replayPreBindLoginPtyRecords(route);
return {
onData(listener: (chunk: string) => void): void {
route.listener = listener;
if (route.buffered.length > 0) {View on GitHub (pinned to 01ad858492)
Solutions
- Inspect worker logs for malformed open replies or crashes during PTY open
- Retry opening the login PTY route once; state machine resets via terminalizeLoginPtyRoute
- Update/upgrade the plugin worker so open replies always carry a bindable session id
- Serialize close/terminalize against open replies to avoid the route leaving `opening` before the reply is processed
Defensive patterns
Strategy: retry
Try / catch
try {
const handle = await createPluginWorkerHandle({ kind: 'login-pty', route });
} catch (e) {
if ((e as Error).message === 'LOGIN_PTY_OPEN_FAILED') {
// route was terminalized; safe to retry the open once
} else throw e;
} Prevention
- Keep worker adapters conformant: open replies must always carry a bindable session id
- Avoid closing/terminalizing a route while its open reply is in flight
- Add integration tests for duplicate and late open replies
- Update workers before changing the open-reply protocol
When it happens
Trigger: Worker returns an open reply lacking a usable session id; the open result references a route whose state is no longer `opening`; a duplicate open reply arrives after a prior one already advanced the state machine.
Common situations: Plugin worker crashed mid-open and sent a truncated reply; race between a close/terminalize request and the in-flight open reply; buggy worker adapter emitting a nonconforming open response; timeouts on the worker side.
Related errors
- The duplex channel launch command needs at least one argumen
- Completed warm transition template conflicts with its exact
- Warm transition result is not yet authenticated.
- Warm run transition target conflicts with its durable receip
- Warm run transition template conflicts with its exact comman
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/c2b7e7515a5ca1b9.
Report an issue: GitHub.