stablyai/orca · error · Error
Runtime environment pairing changed; refresh and try again
Error message
Runtime environment pairing changed; refresh and try again
What it means
Thrown at the start of a remote runtime subscription when args.expectedEnvironmentPairingRevision is provided and does not match the environment's current pairingRevision (falling back to createdAt). This is an optimistic-concurrency guard: pairing revisions change whenever the environment is paired/re-paired to a host, so a mismatch means the client's view is stale.
Source
Thrown at src/main/ipc/runtime-environments.ts:111
}
): Promise<{ subscriptionId: string; requestId: string }> => {
const subscriptionId =
typeof args.subscriptionId === 'string' && args.subscriptionId.length > 0
? args.subscriptionId
: randomUUID()
if (remoteRuntimeSubscriptions.has(subscriptionId)) {
throw new Error('Runtime environment subscription id already exists')
}
const environment = resolveEnvironment(getUserDataPath(), args.selector)
if (isRuntimeEnvironmentManuallyDisconnected(environment.id)) {
throw new Error('runtime_manually_disconnected')
}
const pairingRevision = environment.pairingRevision ?? environment.createdAt
if (
args.expectedEnvironmentPairingRevision !== undefined &&
pairingRevision !== args.expectedEnvironmentPairingRevision
) {
throw new Error('Runtime environment pairing changed; refresh and try again')
}
const transportGeneration = getRuntimeEnvironmentTransportGeneration(environment.id)
const transportIsCurrent = (): boolean =>
getRuntimeEnvironmentTransportGeneration(environment.id) === transportGeneration
const sender = event.sender
const ownerWebContentsId = sender.id
let senderDestroyed = sender.isDestroyed()
let subscription: RemoteRuntimeSubscription | null = null
let destroyedListenerAttached = false
const removeDestroyedListener = (): void => {
if (!destroyedListenerAttached) {
return
}
destroyedListenerAttached = false
sender.removeListener('destroyed', closeSubscription)
}
const closeSubscription = (): void => {
senderDestroyed = trueView on GitHub (pinned to 1136503c6a)
Solutions
- Catch the error, re-resolve the environment to refresh pairingRevision, and retry the subscription once.
- Do not cache pairingRevision beyond the current view; fetch it fresh before subscribing.
- Subscribe to runtime environment change events to invalidate the cached revision proactively.
- If retries keep failing, prompt the user to re-pair the environment.
Example fix
// before
ipc.invoke('runtimeEnvironments:subscribe', { selector, expectedEnvironmentPairingRevision: cached })
// after
try {
await ipc.invoke('runtimeEnvironments:subscribe', { selector, expectedEnvironmentPairingRevision: cached })
} catch (e) {
if (!/pairing changed/.test(e.message)) throw e
const fresh = await ipc.invoke('runtimeEnvironments:resolve', { selector })
await ipc.invoke('runtimeEnvironments:subscribe', {
selector,
expectedEnvironmentPairingRevision: fresh.pairingRevision ?? fresh.createdAt,
})
} Defensive patterns
Strategy: retry
Validate before calling
const env = await ipc.invoke('runtimeEnvironments:resolve', { selector })
const rev = env.pairingRevision ?? env.createdAt
// pass rev as expectedEnvironmentPairingRevision; refresh env before each attempt
await ipc.invoke('runtimeEnvironments:subscribe', { selector, expectedEnvironmentPairingRevision: rev }) Type guard
function hasPairingRevision(env: { pairingRevision?: unknown; createdAt: unknown }): boolean {
return typeof env.pairingRevision !== 'undefined' || typeof env.createdAt !== 'undefined'
} Try / catch
async function subscribe(selector: string, rev: unknown) {
try {
return await ipc.invoke('runtimeEnvironments:subscribe', { selector, expectedEnvironmentPairingRevision: rev })
} catch (e) {
if (!/pairing changed/.test((e as Error).message)) throw e
const fresh = await ipc.invoke('runtimeEnvironments:resolve', { selector })
return ipc.invoke('runtimeEnvironments:subscribe', {
selector,
expectedEnvironmentPairingRevision: fresh.pairingRevision ?? fresh.createdAt,
})
}
} Prevention
- Do not cache pairingRevision beyond the current view; fetch fresh before subscribing.
- Invalidate the cached revision when runtime environment change events fire.
- Retry at most once after a refresh to avoid loops.
When it happens
Trigger: Opening a remote runtime stream with a cached pairingRevision while the environment was re-paired (e.g. reconnection, re-keying, or server-side rotation) in another window or session. The handler also pre-checks manual-disconnect and duplicate subscription id before reaching this guard.
Common situations: Multiple windows where one re-pairs the environment; a long-open client whose cached revision aged out; automated re-pair flows during a session; restored session state pointing at an old revision.
Related errors
- Invalid local log tail subscription id
- Choose another Active Server in Advanced before removing thi
- Invalid Active Server preference
- ${name} exited before readiness: ${containerLogs.stdout}${co
- ${name} did not emit readiness within ${startupTimeoutMs}ms:
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/017a6c1955bcb951.
Report an issue: GitHub.