stablyai/orca · error · Error

Access denied: GitLab source host does not match repository

Error message

Access denied: GitLab source host does not match repository host

What it means

Thrown by assertRegisteredRepo in gitlab.ts:87 when the repo IS registered but the source-context host check fails: args.sourceContext.provider === 'gitlab' and args.sourceContext.hostId !== getRepoExecutionHostId(repo). This prevents a task fetched from one execution host from mutating a same-path repo on a different host.

Source

Thrown at src/main/ipc/gitlab.ts:93

  }
  const resolvedRepoPath = resolve(args.repoPath)
  return store.getRepos().find((r) => resolve(r.path) === resolvedRepoPath)
}

// Why: mirror github.ts assertRegisteredRepo — main-process handlers
// must never operate on a path the user hasn't explicitly registered as
// a repo (filesystem-auth boundary). Source context adds a host check so a
// task fetched from one machine cannot mutate a same-path repo on another.
function assertRegisteredRepo(args: GitLabRepoSelectorArgs, store: Store): Repo {
  const repo = findRegisteredGitLabRepo(args, store)
  if (!repo) {
    throw new Error('Access denied: unknown repository path')
  }
  if (
    args.sourceContext?.provider === 'gitlab' &&
    args.sourceContext.hostId !== getRepoExecutionHostId(repo)
  ) {
    throw new Error('Access denied: GitLab source host does not match repository host')
  }
  return repo
}

function repoConnectionId(repo: Repo): string | null {
  return repo.connectionId ?? null
}

function localGitOptionArgs(store: Store, repo: Repo): [] | [LocalGitExecOptions] {
  const localGitOptions = getLocalProjectWorktreeGitOptions(store, repo)
  return localGitOptions.wslDistro ? [{ wslDistro: localGitOptions.wslDistro }] : []
}

function hostedReviewOptionArgs(store: Store, repo: Repo): [] | [HostedReviewExecutionOptions] {
  const localGitOptions = getLocalProjectWorktreeGitOptions(store, repo)
  return localGitOptions.wslDistro
    ? [{ localGitExecOptions: { wslDistro: localGitOptions.wslDistro } }]
    : []

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Run the GitLab operation against the repo on the host recorded in sourceContext.hostId (the originating host).
  2. If the host genuinely changed, update the repo's execution host association and refresh sourceContext.hostId to match getRepoExecutionHostId(repo).
  3. Strip sourceContext when intentionally retargeting a task to a different host (do so only with explicit user intent).
  4. Validate that the active connection/host matches the task's source host before dispatching the GitLab IPC call.

Example fix

// before
assertRegisteredRepo({ repoPath, sourceContext: { provider: 'gitlab', hostId: taskHostId } }, store)

// after — only dispatch when host matches the registered repo's execution host
const repo = findRegisteredGitLabRepo({ repoPath }, store)
if (getRepoExecutionHostId(repo) !== taskHostId) {
  throw new Error(`retarget to host ${getRepoExecutionHostId(repo)} or drop sourceContext`)
}
assertRegisteredRepo({ repoPath, sourceContext: { provider: 'gitlab', hostId: taskHostId } }, store)
Defensive patterns

Strategy: validation

Validate before calling

// Before a GitLab IPC call carrying sourceContext: confirm host alignment
import { getRepoExecutionHostId } from '../../shared/execution-host'

function gitLabHostMatches(store, args) {
  const repo = store.getRepos().find((r) => resolve(r.path) === resolve(args.repoPath))
  if (!repo) return { kind: 'unregistered' }
  if (args.sourceContext?.provider === 'gitlab' && args.sourceContext.hostId !== getRepoExecutionHostId(repo)) {
    return { kind: 'host-mismatch', expected: getRepoExecutionHostId(repo), got: args.sourceContext.hostId }
  }
  return { kind: 'ok' }
}

Type guard

export function hasGitLabSourceContext(
  args: unknown
): args is { repoPath: string; sourceContext: { provider: 'gitlab'; hostId: string } } {
  return (
    typeof args === 'object' && args !== null &&
    (args as any).sourceContext?.provider === 'gitlab' &&
    typeof (args as any).sourceContext?.hostId === 'string'
  )
}

Try / catch

try {
  await ipcRenderer.invoke('gl:something', { repoPath, sourceContext })
} catch (e) {
  if (e instanceof Error && e.message === 'Access denied: GitLab source host does not match repository host') {
    promptHostRetarget(sourceContext.hostId); return
  }
  throw e
}

Prevention

When it happens

Trigger: A GitLab operation carries sourceContext = { provider: 'gitlab', hostId: H1 } but the matched repo's execution host is H2 (different SSH target / different machine). The path matches a registered repo, but it belongs to a different host than the one the task originated from.

Common situations: Same repo path exists on two machines (e.g. both have ~/code/app); a GitLab task captured on host A is replayed on host B; SSH target changed/reconnected under a new hostId; stale sourceContext persisted across a host reconfiguration.

Understand the failure class

Related errors


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