stablyai/orca · error · Error

Access denied: unknown repository

Error message

Access denied: unknown repository

What it means

Thrown by assertRegisteredRepo in hosted-review.ts:21 on the repoId branch: store.getRepo(repoId) returns no repo, OR the returned repo's path does not equal the supplied repoPath. This guards hosted-review (PR) handlers so a repoId that is unknown or whose path disagrees with the request is rejected as 'Access denied: unknown repository'.

Source

Thrown at src/main/ipc/hosted-review.ts:27

import type { Repo } from '../../shared/types'
import type { Store } from '../persistence'
import type { StatsCollector } from '../stats/collector'
import {
  createHostedReview,
  getHostedReviewCreationEligibility
} from '../source-control/hosted-review-creation'
import { createStackedHostedReview } from '../source-control/stacked-hosted-review-creation'
import { getHostedReviewForBranch } from '../source-control/hosted-review'
import { resolveRegisteredWorktreePath } from './filesystem-auth'
import { listRepoWorktrees } from '../repo-worktrees'
import { getLocalProjectWorktreeGitOptions } from '../project-runtime-git-options'
import { getWorktreeSharedLinkPaths } from '../git/worktree-shared-directories'

function assertRegisteredRepo(repoPath: string, store: Store, repoId?: string): Repo {
  if (repoId) {
    const repo = store.getRepo(repoId)
    if (!repo || repo.path !== repoPath) {
      throw new Error('Access denied: unknown repository')
    }
    return repo
  }
  const resolvedRepoPath = resolve(repoPath)
  const repo = store.getRepos().find((r) => resolve(r.path) === resolvedRepoPath)
  if (!repo) {
    throw new Error('Access denied: unknown repository path')
  }
  return repo
}

async function resolveHostedReviewWorktreePath(
  repo: Repo,
  store: Store,
  worktreePath?: string
): Promise<string> {
  if (!worktreePath) {
    return repo.path

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Re-resolve the repoId from the current store for the given path before calling (e.g. look up by path), then retry.
  2. If the repo was re-added, refresh persisted references to the new repoId.
  3. Drop the repoId and let the path-based lookup (hosted-review.ts:31) handle it when the id is untrusted.
  4. Validate id/path consistency at the call site before dispatching.

Example fix

// before
assertRegisteredRepo(repoPath, store, persistedRepoId)

// after — reconcile id against path before asserting
const byPath = store.getRepos().find((r) => resolve(r.path) === resolve(repoPath))
if (!byPath) throw new Error('repo not registered')
assertRegisteredRepo(repoPath, store, byPath.id)
Defensive patterns

Strategy: validation

Validate before calling

// Before a hosted-review IPC call keyed by repoId: reconcile id with path
import { resolve } from 'node:path'

function reconcileRepoId(store, repoPath, repoId) {
  if (!repoId) return store.getRepos().find((r) => resolve(r.path) === resolve(repoPath))?.id
  const repo = store.getRepo(repoId)
  return repo && resolve(repo.path) === resolve(repoPath) ? repoId : undefined
}

Type guard

export function isHostedReviewRepoRef(
  args: unknown
): args is { repoPath: string; repoId?: string } {
  return typeof args === 'object' && args !== null && typeof (args as any).repoPath === 'string'
}

Try / catch

try {
  await ipcRenderer.invoke('hostedReview:something', { repoPath, repoId })
} catch (e) {
  if (e instanceof Error && e.message === 'Access denied: unknown repository') {
    const freshId = reconcileRepoId(store, repoPath, repoId); promptRefreshRepoId(freshId); return
  }
  throw e
}

Prevention

When it happens

Trigger: A hosted-review IPC handler calls assertRegisteredRepo(repoPath, store, repoId) with a repoId. Denied when store.getRepo(repoId) is falsy, or when the found repo's repo.path !== repoPath. The id/path pair is inconsistent.

Common situations: Stale repoId persisted after the repo was removed and re-added (new id); repoPath drifted (moved/symlink) while repoId stayed; cross-host replay with a repoId from a different store; manually edited/corrupted repoId.

Understand the failure class

Related errors


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