{"record":{"id":"4eed6310fde40a1e","repo":"stablyai/orca","slug":"ssh-target-input-target-connectionid-is-not-c","errorCode":null,"errorMessage":"SSH target \"${input.target.connectionId}\" is not connected.","messagePattern":"SSH target \"(.+?)\" is not connected\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/main/automations/external-manager.ts","lineNumber":359,"sourceCode":"      runs: []\n    }\n  }\n  if (input.target.type === 'local') {\n    const result = await readHermesCronOutputRunsPage(input.jobId, { page, pageSize })\n    return {\n      managerId: input.managerId,\n      provider: input.provider,\n      target: input.target,\n      jobId: input.jobId,\n      page,\n      pageSize,\n      total: result.total,\n      runs: mapHermesJobs(input.managerId, [{ id: input.jobId, runs: result.runs }])[0]?.runs ?? []\n    }\n  }\n  const mux = getActiveMultiplexer(input.target.connectionId)\n  if (!mux || mux.isDisposed()) {\n    throw new Error(`SSH target \"${input.target.connectionId}\" is not connected.`)\n  }\n  const result = (await mux.request('externalAutomations.runs', {\n    provider: input.provider,\n    jobId: input.jobId,\n    page,\n    pageSize\n  })) as { total?: number; runs?: unknown[] }\n  return {\n    managerId: input.managerId,\n    provider: input.provider,\n    target: input.target,\n    jobId: input.jobId,\n    page,\n    pageSize,\n    total: typeof result.total === 'number' && Number.isFinite(result.total) ? result.total : 0,\n    runs:\n      mapHermesJobs(input.managerId, [{ id: input.jobId, runs: result.runs ?? [] }])[0]?.runs ?? []\n  }","sourceCodeStart":341,"sourceCodeEnd":377,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/automations/external-manager.ts#L341-L377","documentation":"Thrown by listExternalAutomationRuns() on the remote branch when getActiveMultiplexer(input.target.connectionId) returns nothing (or a disposed multiplexer). The SSH connection backing the target must be live before Hermes run listings can be requested over it. This is the remote-path precondition; the local Hermes path does not need a mux.","triggerScenarios":"Listing runs for an SSH target whose connection dropped, was never opened, or whose multiplexer was disposed after the UI cached the target. Also if connectionId refers to a closed/disconnected session.","commonSituations":"SSH session timed out or the network dropped between opening the automation view and listing runs; user selected a target whose connection was closed in another pane; relay/SSH host restarted.","solutions":["Reconnect the SSH target (re-open the connection so getActiveMultiplexer returns a live mux) and retry.","Guard the call: check the mux is alive before invoking, and prompt the user to reconnect if not.","Verify input.target.connectionId matches an active, non-disposed multiplexer."],"exampleFix":"// before\nlistExternalAutomationRuns({ target: { connectionId, type: 'remote' }, ... }) // mux gone -> throws\n\n// after\nconst mux = getActiveMultiplexer(connectionId)\nif (!mux || mux.isDisposed()) {\n  await promptReconnect(connectionId)\n  return\n}\nlistExternalAutomationRuns({ target: { connectionId, type: 'remote' }, ... })","handlingStrategy":"validation","validationCode":"import { getActiveMultiplexer } from '...'\n\nfunction isSshTargetLive(connectionId: string): boolean {\n  const mux = getActiveMultiplexer(connectionId)\n  return Boolean(mux) && !mux!.isDisposed()\n}\n\nif (input.target.type === 'remote' && !isSshTargetLive(input.target.connectionId)) {\n  await promptReconnect(input.target.connectionId)\n  return\n}\nlistExternalAutomationRuns(input)","typeGuard":"function isLiveMux(m: { isDisposed: () => boolean } | null | undefined): m is { isDisposed: () => boolean } {\n  return Boolean(m) && !m!.isDisposed()\n}","tryCatchPattern":"try {\n  return await listExternalAutomationRuns(input)\n} catch (e) {\n  if (/SSH target \".+\" is not connected\\./.test((e as Error).message)) {\n    await reconnect(input.target.connectionId)\n    return await listExternalAutomationRuns(input)\n  }\n  throw e\n}","preventionTips":["Subscribe to connection lifecycle events and disable remote-automation actions when the mux is disposed.","Re-check mux liveness immediately before each remote call, not just on view mount.","Clear cached connectionIds when an SSH session closes so stale targets are not selectable."],"tags":["automations","ssh","connection","precondition","remote"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}