stablyai/orca · error · Error

Invalid host ID

Error message

Invalid host ID: ${args.hostId}

What it means

Thrown by the repos:removeForHost IPC handler when normalizeExecutionHostId(args.hostId) returns null. normalizeExecutionHostId delegates to parseExecutionHostId and returns only the canonical id string, so the same three valid forms apply (local literal, ssh:<encoded>, runtime:<encoded>). This handler exists to forget a project on one host without disturbing the same repo id elsewhere.

Solutions

  1. Resolve the host id via normalizeExecutionHostId in the renderer and block the action if it is null.
  2. Use toSshExecutionHostId / toRuntimeExecutionHostId to build the id from a stored target/environment id.
  3. If the host is gone, fall back to repos:remove only after explicit user confirmation (it affects all hosts).
  4. Ensure the host context is captured when the project row is created, not recomputed lazily.

Example fix

// before
ipc.invoke('repos:removeForHost', { repoId, hostId: targetId })

// after
import { normalizeExecutionHostId } from '@shared/execution-host'
const hostId = normalizeExecutionHostId(rawHost)
if (!hostId) {
  showError('This host can no longer be identified.')
  return
}
ipc.invoke('repos:removeForHost', { repoId, hostId })
Defensive patterns

Strategy: type-guard

Validate before calling

import { normalizeExecutionHostId } from '@shared/execution-host'

const hostId = normalizeExecutionHostId(rawHostId)
if (!hostId) {
  showError('Cannot forget on this host: host identity is missing.')
  return
}
await ipc.invoke('repos:removeForHost', { repoId, hostId })

Type guard

import { normalizeExecutionHostId } from '@shared/execution-host'

function isConcreteHostId(value: unknown): value is string {
  return typeof value === 'string' && normalizeExecutionHostId(value) !== null
}

Try / catch

try {
  await ipc.invoke('repos:removeForHost', { repoId, hostId })
} catch (e) {
  if (/Invalid host ID/.test((e as Error).message)) {
    promptForgetAllHosts(repoId) // fallback after explicit consent
  } else throw e
}

Prevention

When it happens

Trigger: Sending a hostId that is undefined/null/empty, a bare target/environment id, or a malformed prefixed string. Because removeForHost must scope the deletion to one host, an unresolvable host id is fatal rather than defaulted to 'all hosts'.

Common situations: A 'forget' action whose host context was lost (e.g. the row was rendered for a host that disconnected); passing the repo's host field verbatim when it actually stores a target id; renderer reused an all-hosts sentinel where a concrete id was required.

Related errors


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

Appendix: source

Thrown at src/main/ipc/repos.ts:2094

        return { status: 'applied' }
      }
      return { status: 'rejected' }
    }
  )

  ipcMain.handle('repos:remove', async (_event, args: { repoId: string }) => {
    store.removeProject(args.repoId)
    invalidateAuthorizedRootsCache()
    notifyReposChanged(mainWindow)
  })

  // Why: forget a project on one execution host without disturbing the same repo id on other hosts (SSH-workspace forget flow).
  ipcMain.handle(
    'repos:removeForHost',
    async (_event, args: { repoId: string; hostId: string }) => {
      const hostId = normalizeExecutionHostId(args.hostId)
      if (!hostId) {
        throw new Error(`Invalid host ID: ${args.hostId}`)
      }
      store.removeProjectForHost(args.repoId, hostId)
      invalidateAuthorizedRootsCache()
      notifyReposChanged(mainWindow)
    }
  )

  ipcMain.handle(
    'repos:update',
    (
      _event,
      args: {
        repoId: string
        hostId?: ExecutionHostId
        updates: Partial<
          Pick<
            Repo,
            | 'displayName'

View on GitHub (pinned to 1136503c6a)