stablyai/orca · error
SSH relay providers were not ready for target "${targetId}".
Error message
SSH relay providers were not ready for target "${targetId}". What it means
Thrown by waitForRuntimeSshProviders when the full SSH_PROVIDER_READY_TIMEOUT_MS (10s, polled every 100ms) elapses without both getSshGitProvider(targetId) and getSshFilesystemProvider(targetId) becoming truthy. The relay accepted the connection and connectRegisteredSshTarget returned 'connected', but the provider-registration side never published both providers, so the runtime cannot route git or filesystem operations over the target. The runtime-owned target is then removed to avoid orphaning it.
Source
Thrown at src/main/ephemeral-vm-runtime-ssh.ts:70
export async function removeRuntimeOwnedSshTarget(targetId: string | undefined): Promise<void> {
if (!targetId) {
return
}
await removeRegisteredSshTarget(targetId)
}
async function waitForRuntimeSshProviders(targetId: string, signal?: AbortSignal): Promise<void> {
const startedAt = Date.now()
while (Date.now() - startedAt < SSH_PROVIDER_READY_TIMEOUT_MS) {
if (signal?.aborted) {
throw new Error(`SSH provider wait aborted for target "${targetId}".`)
}
if (getSshGitProvider(targetId) && getSshFilesystemProvider(targetId)) {
return
}
await new Promise((resolve) => setTimeout(resolve, SSH_PROVIDER_READY_INTERVAL_MS))
}
throw new Error(`SSH relay providers were not ready for target "${targetId}".`)
}
View on GitHub (pinned to 1136503c6a)
Solutions
- Check that the SSH relay process is alive and that its handler registration path actually ran for this targetId (look for registerSshGitProvider / registerSshFilesystemProvider calls in logs).
- Reconnect the SSH target from the UI — a fresh connect attempt re-runs the registration handshake and usually clears a one-off race.
- If provider bootstrap is legitimately slow on this host, confirm whether SSH_PROVIDER_READY_TIMEOUT_MS is being exceeded because of system load (fix the load) rather than bumping the budget.
- Verify the SSH runtime build matches the host: a host that does not send the provider-ready frames (older firmware / relay version) will never satisfy the wait.
Example fix
// before
await connectRuntimeOwnedSshTarget({ runtimeId, connection })
// after: retry once on 'providers not ready', surface a reconnect prompt if it persists
try {
await connectRuntimeOwnedSshTarget({ runtimeId, connection })
} catch (error) {
if (error instanceof Error && error.message.includes('were not ready')) {
await disconnectRuntimeOwnedSshTarget(targetId)
throw new Error('SSH relay providers did not register in time. Reconnect the SSH target.')
}
throw error
} Defensive patterns
Strategy: retry
Validate before calling
import { getSshGitProvider, getSshFilesystemProvider } from '../providers/ssh-git-dispatch'
import { getSshFilesystemProvider as getFs } from '../providers/ssh-filesystem-dispatch'
// Pre-check before relying on a connectionId: both providers must be live.
function sshProvidersReady(connectionId: string): boolean {
return Boolean(getSshGitProvider(connectionId) && getFs(connectionId))
} Type guard
function isSshProvidersNotReady(error: unknown): boolean {
return error instanceof Error && error.message.startsWith('SSH relay providers were not ready for target ')
} Try / catch
async function connectWithRetry(args, attempts = 2): Promise<RuntimeOwnedSshConnectionResult> {
for (let i = 0; i < attempts; i++) {
try { return await connectRuntimeOwnedSshTarget(args) }
catch (error) {
if (isSshProvidersNotReady(error) && i < attempts - 1) {
await disconnectRuntimeOwnedSshTarget(undefined) // best-effort
await new Promise((r) => setTimeout(r, 500))
continue
}
throw error
}
}
throw new Error('unreachable')
} Prevention
- After a connect, verify sshProvidersReady(targetId) before queueing git/filesystem work that assumes the relay is up.
- Prompt an explicit reconnect from the UI on this error rather than silently retrying in a loop.
- Investigate relay registration latency on the host if this fires repeatedly — it usually points to a host/relay version mismatch or load issue, not a normal condition.
When it happens
Trigger: connectRuntimeOwnedSshTarget connects the SSH target successfully, but the relay/handlers that should call registerSshGitProvider / registerSshFilesystemProvider for targetId are delayed, dropped, or never fire (handler not registered, IPC race, relay crash after connect). After 10s of polling, the loop at ephemeral-vm-runtime-ssh.ts:61 exits and throws at :70.
Common situations: SSH handlers are not registered (getSshConnectionStore returned a store but the provider dispatch wiring is incomplete in the running build); the relay process died after the connect handshake but before provider registration; high system load / slow first exec makes provider bootstrap exceed 10s; a version skew between client and SSH host where the host never sends the frames that trigger registration.
Related errors
- SSH provider wait aborted for target "${targetId}".
- Timed out waiting for ${description}
- ${RPC error message}
- SSH target did not connect: ${state.status}
- SSH Git provider is not available. Reconnect to this target
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/a06961f93b56724c.
Report an issue: GitHub.