{"record":{"id":"3f58534c7ab7795e","repo":"stablyai/orca","slug":"clone-aborted","errorCode":null,"errorMessage":"Clone aborted","messagePattern":"Clone aborted","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"info","filePath":"src/main/ipc/repos.ts","lineNumber":550,"sourceCode":"    // Why: match local clone by creating the parent first, or a fresh remote parent surfaces as spawn ENOENT.\n    await fsProvider.createDir(trimmedDestination)\n    // Why: the SSH relay runs git argv, not a shell; use the repo folder name so git creates it under the chosen parent.\n    await gitProvider.clone(\n      ['clone', '--progress', '--', args.url.trim(), repoName],\n      trimmedDestination,\n      {\n        signal: controller.signal,\n        timeoutMs: 10 * 60_000,\n        onProgress: (progress) => {\n          if (!mainWindow.isDestroyed()) {\n            mainWindow.webContents.send('repos:clone-progress', progress)\n          }\n        }\n      }\n    )\n  } catch (err) {\n    if (controller.signal.aborted) {\n      throw new Error('Clone aborted')\n    }\n    const message = err instanceof Error ? err.message : String(err)\n    if (message.startsWith('Clone failed:')) {\n      throw new Error(`Clone failed: ${getGitCloneFailureMessage(message, { clonePath })}`)\n    }\n    throw err\n  } finally {\n    if (activeRemoteClone === metadata) {\n      activeRemoteClone = null\n    }\n    remoteCloneInFlightByPath.delete(remoteCloneKey)\n  }\n  if (existing && isFolderRepo(existing)) {\n    const updated = store.updateRepo(existing.id, {\n      kind: 'git',\n      projectHostSetupMethod: 'cloned'\n    })\n    if (updated) {","sourceCodeStart":532,"sourceCodeEnd":568,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/ipc/repos.ts#L532-L568","documentation":"Thrown in the clone catch block when controller.signal.aborted is true. The AbortController is created per clone and its signal is passed to gitProvider.clone; abort can be triggered by the clone-cancel IPC, by a newer clone superseding this one, or by teardown. The 'Clone aborted' message distinguishes a user/system-initiated cancel from a git failure (which goes through the 'Clone failed:' branch).","triggerScenarios":"controller.abort() was called during gitProvider.clone. Concretely: the user clicked cancel; the activeRemoteClone metadata was replaced by a new clone that aborts the prior one; window/app teardown aborted in-flight clones; the AbortController's signal fired for any other reason.","commonSituations":"User clicked 'Cancel' on the clone progress UI; a second clone to the same destination superseded the first; main window closed mid-clone; abort signal chained from a parent operation.","solutions":["Treat as informational, not an error: the abort was intentional; surface 'Clone canceled' to the user.","If unintended, audit who called controller.abort() — check the cancel IPC handler and any superseding-clone logic.","Ensure no automatic retry fires on 'Clone aborted' (retry only on 'Clone failed:' or rethrown err).","On teardown, accept the abort as expected and skip showing it as an error."],"exampleFix":"// before\ncatch (err) {\n  showUserError(err.message)\n}\n\n// after — distinguish abort from real failure\nimport { abortController } from './clone-state'\ncatch (err) {\n  if (controller.signal.aborted) {\n    showUserToast('Clone canceled')\n    return\n  }\n  showUserError(err.message)\n}","handlingStrategy":"try-catch","validationCode":"// Nothing to validate pre-call — abort is initiated by the caller. Track the controller instead.\nconst controller = new AbortController()\nwindow.addEventListener('beforeunload', () => controller.abort())","typeGuard":"function isCloneAborted(err: unknown): boolean {\n  return err instanceof Error && err.message === 'Clone aborted'\n}","tryCatchPattern":"try {\n  await gitProvider.clone(['clone', '--progress', '--', url, repoName], destination, { signal: controller.signal })\n} catch (err) {\n  if (controller.signal.aborted) {\n    surfaceToast('Clone canceled')\n    return\n  }\n  throw err\n}","preventionTips":["Distinguish 'Clone aborted' from 'Clone failed:' in error UIs — only the latter is a real failure.","Do not auto-retry on abort; the cancel was intentional (user or teardown).","Always run the clone's finally block so remoteCloneInFlightByPath clears even on abort."],"tags":["ssh","clone","abort","cancel","user-initiated"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}