{"record":{"id":"ec701e99a56cecb1","repo":"stablyai/orca","slug":"access-denied-unknown-repository-or-worktree-path","errorCode":null,"errorMessage":"Access denied: unknown repository or worktree path","messagePattern":"Access denied: unknown repository or worktree path","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ipc/filesystem-auth.ts","lineNumber":434,"sourceCode":"  if (registeredWorktreeRoots.has(resolvedTarget) || isRepoRoot(store.getRepos(), resolvedTarget)) {\n    return resolvedTarget\n  }\n\n  if (registeredWorktreeRootsDirty) {\n    await ensureAuthorizedRootsCache(store)\n  }\n\n  if (registeredWorktreeRoots.has(resolvedTarget)) {\n    return resolvedTarget\n  }\n\n  // Resolve symlinks only after the cheap registered-root check: on macOS realpath() can trigger TCC prompts.\n  const normalizedTarget = await normalizeExistingPath(resolvedTarget)\n  if (registeredWorktreeRoots.has(normalizedTarget)) {\n    return normalizedTarget\n  }\n\n  throw new Error('Access denied: unknown repository or worktree path')\n}\n\nfunction refreshRegisteredWorktreeRoots(): void {\n  registeredWorktreeRoots.clear()\n  for (const roots of registeredWorktreeRootsByRepo.values()) {\n    for (const root of roots) {\n      registeredWorktreeRoots.add(root)\n    }\n  }\n}\n\nfunction allLocalRepoRootsRegistered(localRepoIds: Set<string>): boolean {\n  for (const repoId of localRepoIds) {\n    if (!registeredWorktreeRootRepoIds.has(repoId)) {\n      return false\n    }\n  }\n  return true","sourceCodeStart":416,"sourceCodeEnd":452,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/ipc/filesystem-auth.ts#L416-L452","documentation":"Thrown by `resolveRegisteredWorktreePath` after all resolution attempts fail: the resolved target is neither in the `registeredWorktreeRoots` set, a repo root, nor normalizes (via `normalizeExistingPath`) to a registered root. Linked worktrees are trusted only when they appear in `git worktree list` registration, not by directory containment, so an unregistered path is rejected even if it looks like a worktree.","triggerScenarios":"Calling `resolveRegisteredWorktreePath(worktreePath, store)` with a path that is not the root of any repo and not a worktree registered via `git worktree list` for any known repo.","commonSituations":"Worktree was created outside Orca and never registered; worktree was deleted/moved and its registration removed between listing and resolution; path points at a subdirectory of a worktree rather than its root; cache is dirty and `ensureAuthorizedRootsCache` did not pick up the repo.","solutions":["Register the worktree with git from its owning repo (`git worktree add`) so it appears in `git worktree list`.","Call `invalidateAuthorizedRootsCache()` after worktree registration changes, then retry.","Pass the worktree root, not a subdirectory; resolve the root first if you hold a child path."],"exampleFix":"// before\nawait resolveRegisteredWorktreePath(childPathInsideWorktree, store)\n\n// after\nconst root = await resolveWorktreeRoot(childPathInsideWorktree)\ninvalidateAuthorizedRootsCache()\nawait resolveRegisteredWorktreePath(root, store)","handlingStrategy":"validation","validationCode":"// Confirm the path is a registered worktree root or repo root before resolving.\nimport { isRepoRoot } from '../repo-worktrees'\ninvalidateAuthorizedRootsCache() // pick up recent registrations\nawait ensureAuthorizedRootsCache(store)\nif (!registeredWorktreeRoots.has(resolve(worktreePath)) && !isRepoRoot(store.getRepos(), resolve(worktreePath))) {\n  // not registered; register via `git worktree add` or pick a registered root\n  return null\n}\nawait resolveRegisteredWorktreePath(worktreePath, store)","typeGuard":"function isRegisteredRoot(p: string, set: Set<string>, repos: Repo[]): boolean {\n  return set.has(p) || isRepoRoot(repos, p)\n}","tryCatchPattern":"try {\n  return await resolveRegisteredWorktreePath(worktreePath, store)\n} catch (e) {\n  if (e instanceof Error && e.message === 'Access denied: unknown repository or worktree path') {\n    // path is not a git-registered worktree; register it or pass its root\n    throw new UnregisteredWorktreeError(e.message)\n  }\n  throw e\n}","preventionTips":["Pass the worktree root, not a subdirectory; resolve the root first.","Run `git worktree list` (or invalidateAuthorizedRootsCache) after adding/removing worktrees.","Remember linked worktrees are trusted by registration, not by directory containment."],"tags":["filesystem","security-boundary","worktree","authorization","git"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}