stablyai/orca · error

SSH target did not connect: ${state.status}

Error message

SSH target did not connect: ${state.status}

What it means

connectRuntimeOwnedSshTarget called connectRegisteredSshTarget and the returned state.status is not 'connected', with no specific error message on the state — so the generic 'did not connect: <status>' is used. The target is removed (idempotently) before rethrow so a failed connect does not orphan a persisted target.

Source

Thrown at src/main/ephemeral-vm-runtime-ssh.ts:33

export type RuntimeOwnedSshConnectionResult = {
  targetId: string
  target: SshTarget
}

export async function connectRuntimeOwnedSshTarget(args: {
  runtimeId: string
  connection: Extract<EphemeralVmRecipeConnection, { type: 'ssh' }>
  signal?: AbortSignal
}): Promise<RuntimeOwnedSshConnectionResult> {
  const store = getSshConnectionStore()
  if (!store) {
    throw new Error('SSH handlers are not registered.')
  }
  const target = store.upsertRuntimeOwnedTarget(args.runtimeId, args.connection.target)
  try {
    const state = await connectRegisteredSshTarget(target.id)
    if (state.status !== 'connected') {
      throw new Error(state.error || `SSH target did not connect: ${state.status}`)
    }
    await waitForRuntimeSshProviders(target.id, args.signal)
  } catch (error) {
    // The target is persisted at upsert, so a failed connect/provider-wait would
    // orphan it; remove it (idempotent) before rethrowing so cleanup is complete.
    await removeRuntimeOwnedSshTarget(target.id).catch(() => undefined)
    throw error
  }
  return { targetId: target.id, target }
}

export async function disconnectRuntimeOwnedSshTarget(targetId: string | undefined): Promise<void> {
  if (!targetId) {
    return
  }
  await disconnectRegisteredSshTarget(targetId)
}

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Catch and log the full state object (status + error) instead of only the generic message.
  2. Verify the SSH target host, port, and key in the connection config.
  3. Ensure the SSH agent has the key (`ssh-add -l`).
  4. Retry after confirming network reachability of the host.

Example fix

// before
const { targetId } = await connectRuntimeOwnedSshTarget(args)

// after
try {
  const { targetId } = await connectRuntimeOwnedSshTarget(args)
} catch (e) {
  throw new Error(`SSH connect failed for ${args.connection.target.host}: ${e.message}`)
}
Defensive patterns

Strategy: try-catch

Validate before calling

const ok = await pingSshHost(args.connection.target.host, args.connection.target.port)
if (!ok) { /* fix host/key/agent before connect */ }

Type guard

function isSshConnectError(e: unknown): boolean {
  return e instanceof Error && /SSH target did not connect|SSH handlers are not registered|provider wait aborted/.test(e.message)
}

Try / catch

try { return await connectRuntimeOwnedSshTarget(args) }
catch (e) {
  if (isSshConnectError(e)) { throw new Error(`SSH connect failed for ${args.connection.target.host}: ${e.message}`) }
  throw e
}

Prevention

When it happens

Trigger: ephemeral-vm-runtime-ssh.ts:31-33 — connectRegisteredSshTarget(target.id) returns a state whose status !== 'connected' AND state.error is empty, hitting the fallback template.

Common situations: SSH auth failure surfaced as a non-error status; host unreachable; the key is not loaded in the ssh agent; connection refused; a provider-registration race where the connection is left in a transitional state.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/ea1dd2ff23f0fa81. Report an issue: GitHub.