stablyai/orca · error
Couldn't verify the SSH connection. Reconnect the host and…
Error message
Couldn't verify the SSH connection. Reconnect the host and try again.
What it means
Thrown by buildMobileFileMutationOwnership when worktreeHostId is a defined non-undefined value but parseExecutionHostId could not parse it into a recognized host (local | runtime | ssh). This guards against committing a file mutation to a host whose execution identity the client cannot interpret — writing through an ambiguous host id would risk mutating the wrong machine.
Solutions
- Update the mobile app so parseExecutionHostId understands the new host-kind prefix.
- If worktreeHostId came from worktree.show, re-fetch it — a corrupt value often indicates a stale worktree row; rotate the worktree.
- Treat as 'reconnect the host': the SSH_OWNER_CHANGED_MESSAGE tells the user to re-establish the host connection so a fresh, parseable hostId is captured.
- If the hostId is genuinely a new kind and updating is not possible, block mutations on that worktree until the app is upgraded.
Example fix
// before
const host = parseExecutionHostId(worktreeHostId)
if (worktreeHostId !== undefined && !host) {
throw new Error(SSH_OWNER_CHANGED_MESSAGE)
}
// after — distinguish 'new kind' from 'corrupt' for clearer UX
const host = parseExecutionHostId(worktreeHostId)
if (worktreeHostId !== undefined && !host) {
if (typeof worktreeHostId === 'string' && worktreeHostId.includes(':')) {
throw new Error(`Unsupported host kind: ${worktreeHostId.split(':')[0]}. Update the app.`)
}
throw new Error(SSH_OWNER_CHANGED_MESSAGE)
} Defensive patterns
Strategy: validation
Validate before calling
// Validate the host id is parseable before building ownership
import { parseExecutionHostId } from '../../../src/shared/execution-host'
if (worktreeHostId !== undefined && !parseExecutionHostId(worktreeHostId)) {
throw new Error('Cannot mutate files: unrecognized host id. Reconnect the host.')
} Type guard
function isRecognizedHostId(id: string | null | undefined): boolean {
if (id === undefined || id === null) return true
return parseExecutionHostId(id) !== null
} Try / catch
try {
return buildMobileFileMutationOwnership(worktreeHostId, sshState)
} catch (err) {
if (err instanceof Error && err.message === SSH_OWNER_CHANGED_MESSAGE) {
await forceReconnect()
const fresh = await captureMobileFileMutationOwnership(client, worktree)
return fresh
}
throw err
} Prevention
- Treat unparseable host ids as a hard stop — never fall back to 'local'.
- When a new host-kind prefix is introduced, update parseExecutionHostId in lockstep.
- Re-capture ownership via captureMobileFileMutationOwnership after any host reconnect.
When it happens
Trigger: buildMobileFileMutationOwnership(worktreeHostId, sshState) is called with worktreeHostId that is defined (not undefined) but not 'local', not a 'runtime:...' id, and not an 'ssh:...' id. Concretely: a malformed host string from worktree.show, a new host-kind prefix the client build does not yet understand, or a corrupted persisted host id.
Common situations: A newer desktop build introduces a new execution-host kind (e.g., 'container:...') that this mobile build's parseExecutionHostId does not recognize; a worktree.show result with a truncated or corrupt hostId; an old mobile app paired with a newer desktop that emits a different host id scheme.
Related errors
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/68186440bdf13072.
Report an issue: GitHub.
Appendix: source
Thrown at mobile/src/files/mobile-file-mutation-ownership.ts:22
import type { SshConnectionState, SshMutationExpectation } from '../../../src/shared/ssh-types'
import type { RpcClient } from '../transport/rpc-client'
import type { RpcFailure, RpcSuccess } from '../transport/types'
const FILE_MUTATION_TIMEOUT_MS = 15_000
const SSH_OWNER_CHANGED_MESSAGE =
"Couldn't verify the SSH connection. Reconnect the host and try again."
export type MobileFileMutationOwnership = SshMutationExpectation & {
expectedExecutionHostId: 'local' | `ssh:${string}`
}
export function buildMobileFileMutationOwnership(
worktreeHostId: string | null | undefined,
sshState: SshConnectionState | null = null
): MobileFileMutationOwnership {
const host = parseExecutionHostId(worktreeHostId)
if (worktreeHostId !== undefined && !host) {
throw new Error(SSH_OWNER_CHANGED_MESSAGE)
}
if (!host || host.kind === 'local' || host.kind === 'runtime') {
return { expectedExecutionHostId: 'local' }
}
if (sshState?.targetId !== host.targetId || sshState.connectionGeneration === undefined) {
throw new Error(SSH_OWNER_CHANGED_MESSAGE)
}
return {
expectedExecutionHostId: host.id,
expectedSshTargetId: host.targetId,
expectedSshConnectionGeneration: sshState.connectionGeneration
}
}
export async function captureMobileFileMutationOwnership(
client: Pick<RpcClient, 'sendRequest'>,
worktree: string
): Promise<MobileFileMutationOwnership> {View on GitHub (pinned to 1136503c6a)