stablyai/orca · error · Error

Invalid host ID: ${args.hostId}

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.

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)

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.