{"record":{"id":"8460e28da2e3e9ce","repo":"stablyai/orca","slug":"normalizegiterrormessage-error-fetch","errorCode":null,"errorMessage":"normalizeGitErrorMessage(error, 'fetch')","messagePattern":"normalizeGitErrorMessage\\(error, 'fetch'\\)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/main/git/remote.ts","lineNumber":312,"sourceCode":"}\n\nexport async function gitFetch(\n  worktreePath: string,\n  pushTarget?: GitPushTarget,\n  options: GitRuntimeOptions = {}\n): Promise<void> {\n  try {\n    if (pushTarget) {\n      const target = await validateGitPushTarget(worktreePath, pushTarget, options)\n      await gitExecFileAsync(\n        ['fetch', '--prune', target.remoteName],\n        gitOptionsForWorktree(worktreePath, options)\n      )\n      return\n    }\n    await gitExecFileAsync(['fetch', '--prune'], gitOptionsForWorktree(worktreePath, options))\n  } catch (error) {\n    throw new Error(normalizeGitErrorMessage(error, 'fetch'))\n  }\n}\n","sourceCodeStart":294,"sourceCodeEnd":315,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/git/remote.ts#L294-L315","documentation":"gitFetch wraps its fetch --prune in a try/catch that rethrows new Error(normalizeGitErrorMessage(error, 'fetch')). The literal message is the source expression; the runtime message is the normalized fetch diagnostic. Because the operation is 'fetch' (not 'push'/'pull'), the push-specific non-fast-forward and submodule hints are skipped — you get auth, network, no-upstream, or the tail stderr line.","triggerScenarios":"Calling gitFetch(worktreePath, pushTarget, options) when the remote is unreachable, credentials are missing/expired, the named remote (pushTarget.remoteName) does not exist, the network drops mid-fetch, or a prune references a remote ref that is concurrently being deleted.","commonSituations":"Expired OAuth token / SSH key for the remote; offline or flaky network; a pushTarget pointing at a fork remote that was removed; fetching right after a remote rename without updating pushTarget; large repos on slow links hitting exec-level stalls.","solutions":["Read the normalized message — auth, network, and no-upstream hints are pre-classified.","For auth: refresh credentials for the target remote (or origin when no pushTarget is set).","For network: retry once; fetch is idempotent and --prune is safe to re-run.","Verify the target remote exists (git remote) before fetching when pushTarget is supplied — a removed fork remote fails here."],"exampleFix":"// before\nawait gitFetch(worktreePath, { remoteName: 'fork', branchName: 'feat' })\n\n// after: verify the remote exists, retry once on transient network failure\nconst remotes = await readRemotes(worktreePath)\nif (!remotes.includes('fork')) throw new Error('Configure the fork remote first')\ntry { await gitFetch(worktreePath, { remoteName: 'fork', branchName: 'feat' }) }\ncatch (error) {\n  if (/(Network error|Could not resolve host)/.test(String(error))) await gitFetch(worktreePath, { remoteName: 'fork', branchName: 'feat' })\n  else throw error\n}","handlingStrategy":"retry","validationCode":"import { getDefaultRemote } from './repo'\n\n// Pre-check the target remote exists before fetching.\nconst { stdout } = await gitExecFileAsync(['remote'], gitExecOptions(worktreePath, {}))\nconst remotes = stdout.split('\\n').map((l) => l.trim()).filter(Boolean)\nconst target = pushTarget?.remoteName ?? await getDefaultRemote(worktreePath).catch(() => null)\nif (target && !remotes.includes(target)) throw new Error(`Remote '${target}' is not configured.`)","typeGuard":"function isFetchAuth(error: unknown): boolean {\n  return error instanceof Error && error.message.startsWith('Authentication failed')\n}\nfunction isFetchNetwork(error: unknown): boolean {\n  return error instanceof Error && error.message.startsWith('Network error')\n}","tryCatchPattern":"try {\n  await gitFetch(worktreePath, pushTarget, options)\n} catch (error) {\n  if (isFetchNetwork(error)) { await gitFetch(worktreePath, pushTarget, options) /* idempotent, safe to retry once */ }\n  else if (isFetchAuth(error)) { await refreshRemoteCreds(worktreePath); await gitFetch(worktreePath, pushTarget, options) }\n  else throw error\n}","preventionTips":["Verify the target remote exists before fetching when supplying pushTarget.","Refresh credentials on auth-class failures; fetch is safe to retry on transient network errors.","Do not rename a remote without updating stored pushTargets."],"tags":["git","fetch","remote","normalized-error"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}