{"record":{"id":"61093849c4a187f3","repo":"stablyai/orca","slug":"clone-failed-message","errorCode":null,"errorMessage":"Clone failed: ${message}","messagePattern":"Clone failed: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ipc/repos.ts","lineNumber":2406,"sourceCode":"        const pendingController = new AbortController()\n        pendingLocalCloneControllers.add(pendingController)\n        try {\n          // Why: use the parent destination as cwd so the runner detects a WSL path and routes through wsl.exe.\n          // Why: '--' isolates the URL so a malicious URL can't be read as git flags (command injection).\n          proc = await gitSpawnAfterWindowsEnvironmentReady(\n            ['clone', '--progress', '--', args.url, clonePath],\n            {\n              cwd: args.destination,\n              // Why: without this, an auth-needing clone pops Git Credential Manager's OAuth window on Windows, unclosable in a restricted env (issue #7652).\n              env: nonInteractiveGitEnv(),\n              signal: pendingController.signal,\n              stdio: ['ignore', 'ignore', 'pipe']\n            }\n          )\n        } catch (err) {\n          await cleanupClaimedCloneTarget(clonePath, claimedTarget)\n          const message = err instanceof Error ? err.message : String(err)\n          throw new Error(`Clone failed: ${message}`)\n        } finally {\n          pendingLocalCloneControllers.delete(pendingController)\n        }\n        await new Promise<void>((resolve, reject) => {\n          const generation = nextCloneGeneration++\n          latestCloneGenerationByPath.set(clonePathKey, generation)\n          const metadata: ActiveCloneMetadata = {\n            path: clonePath,\n            pathKey: clonePathKey,\n            claimedTarget,\n            process: proc,\n            abortRequested: false,\n            generation,\n            pendingAbortCleanup: null,\n            resolvePendingAbortCleanup: null\n          }\n          cloneMetadataRef.current = metadata\n          activeClone = metadata","sourceCodeStart":2388,"sourceCodeEnd":2424,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/ipc/repos.ts#L2388-L2424","documentation":"Thrown when the underlying git clone subprocess fails during repos:clone. The handler cleans up the claimed clone target, extracts the error message from the thrown value (Error.message or String(err)), and re-throws prefixed with 'Clone failed: '. The clone is run with --progress and a nonInteractiveGitEnv() to avoid Git Credential Manager OAuth popups.","triggerScenarios":"Network or auth failure reaching the remote (HTTP 401/403, SSH key rejected), an invalid or unreachable URL, a destination that cannot be written, the abort signal firing (user cancelled), or git not installed / wrong git on PATH.","commonSituations":"Private repo cloned without credentials configured; corporate proxy or firewall blocking the remote; destination path already exists and is non-empty; WSL/SSH host git version too old; user clicked cancel mid-clone.","solutions":["Inspect the captured message after the 'Clone failed: ' prefix — it usually names the real cause (auth, DNS, disk).","For auth issues, configure credentials (SSH agent, credential helper, or PAT) and retry.","Ensure the destination directory is empty and writable before cloning.","If the user cancelled, treat AbortError as non-fatal and skip retry.","On remote hosts, verify the git binary version meets the baseline."],"exampleFix":"// before\ntry {\n  await ipc.invoke('repos:clone', args)\n} catch (e) {\n  notify(e.message)\n}\n\n// after\ntry {\n  await ipc.invoke('repos:clone', args)\n} catch (e) {\n  const cause = e.message.replace(/^Clone failed:\\s*/, '')\n  if (/abort/i.test(cause)) return // user-cancelled\n  if (/auth|403|401|permission/i.test(cause)) promptForCredentials(args.url)\n  else notify(`Clone failed: ${cause}`)\n}","handlingStrategy":"try-catch","validationCode":"import { stat } from 'fs/promises'\nimport { access } from 'fs/promises'\n\nasync function preflightClone(url: string, destination: string): Promise<string | null> {\n  try { await access(destination); return 'Destination already exists.' } catch { /* ok */ }\n  try {\n    const s = await stat(destination)\n    if (!s.isDirectory()) return 'Destination is not a directory.'\n  } catch { /* will be created */ }\n  if (!/^https?:|^git@|^[A-Za-z]+@/.test(url)) return 'Unsupported clone URL scheme.'\n  return null\n}\n\nconst issue = await preflightClone(args.url, args.destination)\nif (issue) { showError(issue); return }\nawait ipc.invoke('repos:clone', args)","typeGuard":"function isAbortFailure(message: string): boolean {\n  return /abort|cancel/i.test(message)\n}","tryCatchPattern":"try {\n  await ipc.invoke('repos:clone', args)\n} catch (e) {\n  const cause = (e as Error).message.replace(/^Clone failed:\\s*/, '')\n  if (/abort|cancel/i.test(cause)) return // user-cancelled\n  if (/auth|401|403|permission denied/i.test(cause)) promptForCredentials(args.url)\n  else showCloneError(cause)\n}","preventionTips":["Configure git credentials (SSH agent / credential helper / PAT) before cloning private repos.","Pre-check the destination is empty and writable.","Verify git is on PATH and meets the version baseline on remote hosts.","Distinguish user aborts from real failures in the UI."],"tags":["ipc","repos","git","clone","network","auth"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}