{"record":{"id":"f0f9cadb95c0f258","repo":"google-gemini/gemini-cli","slug":"failed-to-clone-git-repository-from-installmetad","errorCode":null,"errorMessage":"Failed to clone Git repository from ${installMetadata.source} ${getErrorMessage(error)}","messagePattern":"Failed to clone Git repository from (.+?) (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/config/extensions/github.ts","lineNumber":73,"sourceCode":"    }\n    await git.clone(sourceUrl, './', ['--depth', '1']);\n\n    const remotes = await git.getRemotes(true);\n    if (remotes.length === 0) {\n      throw new Error(\n        `Unable to find any remotes for repo ${installMetadata.source}`,\n      );\n    }\n\n    const refToFetch = installMetadata.ref || 'HEAD';\n\n    await git.fetch(remotes[0].name, refToFetch);\n\n    // After fetching, checkout FETCH_HEAD to get the content of the fetched ref.\n    // This results in a detached HEAD state, which is fine for this purpose.\n    await git.checkout('FETCH_HEAD');\n  } catch (error) {\n    throw new Error(\n      `Failed to clone Git repository from ${installMetadata.source} ${getErrorMessage(error)}`,\n      {\n        cause: error,\n      },\n    );\n  }\n}\n\nexport interface GithubRepoInfo {\n  owner: string;\n  repo: string;\n}\n\nexport function tryParseGithubUrl(source: string): GithubRepoInfo | null {\n  // Handle SCP-style SSH URLs.\n  if (source.startsWith('git@')) {\n    if (source.startsWith('git@github.com:')) {\n      // It's a GitHub SSH URL, so normalize it for the URL parser.","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/google-gemini/gemini-cli/blob/5024443c7217464a66e98f80d73172a26440bd8f/packages/cli/src/config/extensions/github.ts#L55-L91","documentation":"Catch-all wrapper around the entire cloneFromGit try block. Any failure in clone, getRemotes, fetch, or checkout is re-thrown with the source and the underlying message (via getErrorMessage) and the original error attached as cause.","triggerScenarios":"git.clone rejects (auth failure, unreachable host, invalid URL, permission denied on destination), git.fetch rejects (ref does not exist), or git.checkout('FETCH_HEAD') rejects (fetch produced nothing).","commonSituations":"Wrong/expired GitHub token; typo'd source URL; branch/tag in installMetadata.ref that does not exist; destination directory not writable; corporate proxy blocking git; rate-limited by the hoster.","solutions":["Inspect error.cause for the real git failure and address it (fix URL, refresh token, correct ref).","Confirm network/proxy access to the git host and that the destination is writable.","Retry after fixing credentials; for transient failures, retry with backoff."],"exampleFix":"// before\ntry { await cloneFromGit(meta, dest); }\ncatch (e) { /* only sees wrapped message */ }\n// after\ntry { await cloneFromGit(meta, dest); }\ncatch (e) {\n  if (e.cause) console.error('underlying git error:', e.cause);\n  throw e;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { await cloneFromGit(meta, dest); } catch (e) { const cause = (e as Error & {cause?: Error}).cause; logGitFailure(meta.source, cause ?? e); throw e; }","preventionTips":["Check error.cause for the underlying git message before reporting.","Verify token, URL, and ref before invoking clone in automation."],"tags":["extensions","git","network","installation","error-wrapping"],"backgroundTag":null,"analyzedSha":"5024443c7217464a66e98f80d73172a26440bd8f","analyzedAt":"2026-08-12T06:01:53.711Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}