stablyai/orca · error
Failed to terminate SSH host sessions: ${shutdownFailures.jo
Error message
Failed to terminate SSH host sessions: ${shutdownFailures.join('; ')} What it means
Thrown after attempting to shut down remote SSH PTY sessions when one or more provider.shutdown() calls rejected with a reason that is not an 'SSH pty not found' error. Non-not-found failures indicate the remote shell may still be alive in the grace window, so the code intentionally keeps the lease/session intact to let the user retry. The aggregated relayPtyId:reason pairs are joined so the caller can see which specific sessions failed and why.
Source
Thrown at src/main/ipc/ssh.ts:1357
)
)
: []
const shutdownFailures: string[] = []
for (const [index, result] of shutdownResults.entries()) {
const { appPtyId, relayPtyId } = ptyIds[index]
if (result.status !== 'fulfilled' && !isSshPtyNotFoundError(result.reason)) {
shutdownFailures.push(
`${relayPtyId}: ${result.reason instanceof Error ? result.reason.message : String(result.reason)}`
)
continue
}
clearProviderPtyState(appPtyId)
deletePtyOwnership(appPtyId)
persistedStore!.markSshRemotePtyLease(args.targetId, relayPtyId, 'terminated')
}
if (shutdownFailures.length > 0) {
// Why: a failed relay shutdown can leave the remote process alive in the grace window; keep the lease/session so the user can retry.
throw new Error(`Failed to terminate SSH host sessions: ${shutdownFailures.join('; ')}`)
}
await teardownSshTargetTransport(args.targetId, (session) => session.disposeAndPersist())
})
})
async function doResetRelay(targetId: string, target: SshTarget): Promise<void> {
const inFlightConnect = connectInFlight.get(targetId)
if (inFlightConnect) {
try {
// Why: resetting activeSessions mid-deploy would dispose the session doConnect will use.
await inFlightConnect.promise
} catch {
// The reset can still recover a stale remote relay after a failed connect.
}
}
rotateSshProviderAuthority(targetId)
const session = activeSessions.get(targetId)View on GitHub (pinned to 1136503c6a)
Solutions
- Retry the terminate request; transient relay errors often clear on the second attempt.
- Inspect the per-pty reasons in the message to identify which remote host/session is stuck, then address that shell directly (e.g. log in and kill the PID).
- If the relay itself is unhealthy, run 'ssh:resetRelay' first to rebuild the transport, then retry terminate.
- As a last resort for truly wedged remote shells, accept the lease stays and let the remote OS reap the process.
Defensive patterns
Strategy: retry
Try / catch
for (let attempt = 0; attempt < 2; attempt++) {
try {
await ipcRenderer.invoke('ssh:terminateSessions', { targetId })
break
} catch (e) {
if (attempt < 1 && /Failed to terminate SSH host sessions/.test((e as Error).message)) continue
showTerminationFailures((e as Error).message)
throw e
}
} Prevention
- Retry once after a brief delay — transient relay shutdown failures often clear.
- Parse the per-pty failure list from the message to target stuck remote shells.
- Consider ssh:resetRelay if repeated terminate attempts fail with transport errors.
When it happens
Trigger: Promise.allSettled over ptyIds where at least one provider.shutdown(immediate:true, keepHistory:false) rejected with a transport error, timeout, permission error, or unexpected relay response. isSshPtyNotFoundError filtered out only the benign already-gone case.
Common situations: Relay under load returns a transient error. Remote shell is wedged and ignores the shutdown signal within the timeout. Permission/quota issue on the remote host blocks process termination. Partial network partition where some shutdowns succeed and others fail.
Related errors
- SSH_TERMINATE_RECONNECT_REQUIRED
- SSH relay providers were not ready for target "${targetId}".
- SSH Git provider is not available. Reconnect to this target
- SSH connection is reconnecting — please try again in a momen
- Remote connection dropped. Click Reconnect on the SSH target
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/d0ed1192fb3869dc.
Report an issue: GitHub.