{"record":{"id":"47ee9aa9cf8df4c6","repo":"stablyai/orca","slug":"repo-path-must-be-an-absolute-path","errorCode":null,"errorMessage":"Repo path must be an absolute path","messagePattern":"Repo path must be an absolute path","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ipc/repos.ts","lineNumber":1022,"sourceCode":"    scanId: z.string().min(1).optional(),\n    mode: z.literal('separate')\n  })\n])\n\nfunction parseProjectGroupIpcArgs<T>(schema: z.ZodType<T>, value: unknown, errorCode: string): T {\n  const result = schema.safeParse(value)\n  if (result.success) {\n    return result.data\n  }\n  throw new Error(errorCode)\n}\n\nfunction validateNestedRepoScanRoot(path: string, connectionId?: string): void {\n  if (connectionId) {\n    return\n  }\n  if (!isAbsolute(path)) {\n    throw new Error('Repo path must be an absolute path')\n  }\n}\n\nfunction rememberCompletedNestedRepoScan(\n  scanId: string | undefined,\n  context: { parentPath: string; connectionId?: string },\n  scan: NestedRepoScanResult\n): void {\n  if (!scanId) {\n    return\n  }\n  completedNestedRepoScans.set(scanId, {\n    scan,\n    parentPath: scan.selectedPath,\n    connectionId: context.connectionId ?? null\n  })\n  while (completedNestedRepoScans.size > MAX_COMPLETED_NESTED_SCAN_RESULTS) {\n    const oldestScanId = completedNestedRepoScans.keys().next().value","sourceCodeStart":1004,"sourceCodeEnd":1040,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/ipc/repos.ts#L1004-L1040","documentation":"Thrown by validateNestedRepoScanRoot when a nested-repo scan is requested with a non-absolute path on the local host. The guard is skipped entirely when a connectionId (remote/SSH host) is supplied, because absolute-vs-relative is only meaningful for local filesystem scans. The check uses node's isAbsolute and rejects any path that is not rooted.","triggerScenarios":"Calling the nested-repo-scan IPC with a relative or empty path while no connectionId is set. This happens when a renderer passes a workspace-relative path (e.g. \"./subdir\" or \"repos/foo\") instead of a fully resolved local path, or when a folder-workspace path was never resolved against the workspace root before the scan was triggered.","commonSituations":"A folder workspace (non-git) whose base path was not resolved to absolute before the scan; a renderer bug that forwards a tilde path like \"~/code\" unexpanded; passing a worktree-relative path for a local nested scan. Not seen for SSH/remote scans since connectionId short-circuits the check.","solutions":["Resolve the path against an absolute base with path.resolve() (or path.join(root, relative)) before invoking the nested scan IPC.","If the input may contain '~', expand it via os.homedir() before resolving.","Ensure folder-workspace base directories are stored and forwarded in absolute form from the point they are first computed.","Add a renderer-side precondition that rejects relative paths with a user-facing message before the IPC round-trip."],"exampleFix":"// before\nstartNestedRepoScan({ parentPath: relativePath })\n\n// after\nimport { path } from '@tauri-apps/api' // or node path in preload bridge\nconst absolute = path.isAbsolute(relativePath)\n  ? relativePath\n  : path.resolve(workspaceRoot, relativePath)\nstartNestedRepoScan({ parentPath: absolute })","handlingStrategy":"validation","validationCode":"import { isAbsolute, resolve } from 'path'\n\nfunction ensureAbsoluteScanRoot(path: string, workspaceRoot: string): string {\n  if (isAbsolute(path)) return path\n  const resolved = resolve(workspaceRoot, path)\n  if (!isAbsolute(resolved)) {\n    throw new Error('Nested scan root could not be resolved to an absolute path')\n  }\n  return resolved\n}\n\n// before IPC:\nconst parentPath = ensureAbsoluteScanRoot(rawPath, workspaceRoot)\nstartNestedRepoScan({ parentPath /*, connectionId omitted for local */ })","typeGuard":"function isAbsolutePathLocal(p: unknown): p is string {\n  return typeof p === 'string' && p.length > 0 && (p.startsWith('/') || /^[A-Za-z]:[\\\\/]/.test(p))\n}","tryCatchPattern":"try {\n  await startNestedRepoScan({ parentPath })\n} catch (e) {\n  if (/absolute path/i.test((e as Error).message)) {\n    showError('Select a folder inside the workspace root.')\n  } else throw e\n}","preventionTips":["Store all workspace/folder base paths in absolute form from creation.","Resolve any user or paste input through path.resolve against a known root before scanning.","Skip this guard only when connectionId is set (remote host), matching the source's short-circuit."],"tags":["ipc","filesystem","validation","repos","nested-scan"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}