{"record":{"id":"f3ab9c9906791740","repo":"stablyai/orca","slug":"clone-path-must-be-inside-the-destination-director-f3ab9c","errorCode":null,"errorMessage":"Clone path must be inside the destination directory","messagePattern":"Clone path must be inside the destination directory","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ipc/repos.ts","lineNumber":505,"sourceCode":"  if (!gitProvider) {\n    throw new Error(`SSH connection \"${args.connectionId}\" not found or not connected`)\n  }\n  const fsProvider = getSshFilesystemProvider(args.connectionId)\n  if (!fsProvider) {\n    throw new Error(`SSH connection \"${args.connectionId}\" not found or not connected`)\n  }\n  const host = gitProvider.getHostPlatform?.()\n  if (!host) {\n    throw new Error('SSH host platform is unavailable. Reconnect the SSH target before cloning.')\n  }\n  const trimmedDestination = await resolveRemoteHomePath(args.connectionId, args.destination.trim())\n  if (!isRuntimePathAbsolute(trimmedDestination, host.pathFlavor)) {\n    throw new Error('Clone destination must be an absolute path on the SSH host')\n  }\n  const repoName = deriveCloneRepoNameFromUrl(args.url.trim())\n  const clonePath = joinRemotePath(host, trimmedDestination, repoName)\n  if (relativePathInsideRoot(trimmedDestination, clonePath) === null) {\n    throw new Error('Clone path must be inside the destination directory')\n  }\n  const clonePathKey = normalizeRuntimePathForComparison(clonePath)\n  const existing = store.getRepos().find((repo) => {\n    return (\n      repo.connectionId === args.connectionId &&\n      normalizeRuntimePathForComparison(repo.path) === clonePathKey\n    )\n  })\n  if (existing && !isFolderRepo(existing)) {\n    emitRepoAdded('clone_url', true)\n    return existing\n  }\n\n  const remoteCloneKey = `${args.connectionId}:${clonePathKey}`\n  if (remoteCloneInFlightByPath.has(remoteCloneKey)) {\n    throw new Error('A clone is already in progress for this SSH destination')\n  }\n  const controller = new AbortController()","sourceCodeStart":487,"sourceCodeEnd":523,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/ipc/repos.ts#L487-L523","documentation":"Thrown when relativePathInsideRoot(trimmedDestination, clonePath) === null. clonePath is built by joinRemotePath(host, trimmedDestination, repoName) where repoName comes from deriveCloneRepoNameFromUrl. The guard ensures the resulting clone path stays inside the chosen parent. deriveCloneRepoNameFromUrl already rejects '.', '..', and any name containing '/' or '\\\\', so a null result here typically indicates a Windows/UNC or path-traversal edge the join produced an out-of-tree result for.","triggerScenarios":"joinRemotePath produced a clonePath that is not strictly beneath trimmedDestination. Possible with UNC root quirks ('//server/share' as destination where the joined result escapes via normalization), a destination that itself normalizes to a parent of the join, or a repoName that — while not '.' or '..' — interacts with windows drive handling to escape.","commonSituations":"Cloning into a UNC root ('//server/share') where the joined path re-normalizes outside the parent; windows path flavor with a destination that has a trailing separator that joinRemotePath collapses oddly; exotic repo names from URLs that survive deriveCloneRepoNameFromUrl's guards but still misbehave under join.","solutions":["Choose a non-root destination directory with a clear parent (e.g. '/home/user/repos' not '//server/share').","Verify the URL yields a clean repoName via deriveCloneRepoNameFromUrl before calling clone.","Re-test with relativePathInsideRoot(destination, join(destination, repoName)) locally before invoking the clone IPC.","If reproducible, file a bug — deriveCloneRepoNameFromUrl and joinRemotePath are designed to make this branch unreachable."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import { relativePathInsideRoot } from '../../shared/cross-platform-path'\nimport { joinRemotePath } from '../ssh/ssh-remote-platform'\nimport { deriveCloneRepoNameFromUrl } from '../git/repo-clone-path'\nimport type { RemoteHostPlatform } from '../ssh/ssh-remote-platform'\n\nfunction clonePathStaysInsideDestination(\n  url: string,\n  destination: string,\n  host: RemoteHostPlatform\n): boolean {\n  const repoName = deriveCloneRepoNameFromUrl(url.trim())\n  const clonePath = joinRemotePath(host, destination, repoName)\n  return relativePathInsideRoot(destination, clonePath) !== null\n}","typeGuard":"function isClonePathOutsideDestination(err: unknown): boolean {\n  return err instanceof Error && err.message === 'Clone path must be inside the destination directory'\n}","tryCatchPattern":"if (!clonePathStaysInsideDestination(url, trimmedDestination, host)) {\n  surfaceUserAction('Choose a non-root destination directory (avoid UNC roots or paths that re-normalize outside the parent).')\n  return\n}\nawait cloneRemoteRepo(store, mainWindow, { connectionId, url, destination })","preventionTips":["Avoid cloning into a UNC root ('//server/share'); use a subdirectory as the parent.","Run clonePathStaysInsideDestination locally before invoking clone for unusual URLs or Windows hosts.","If the branch fires despite a clean URL, file a bug — deriveCloneRepoNameFromUrl and joinRemotePath are designed to make it unreachable."],"tags":["ssh","clone","path-validation","traversal","unc","filesystem"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}