{"record":{"id":"ebbab79d87dbaad1","repo":"google-gemini/gemini-cli","slug":"failed-to-install-extension-installmetadata-sour","errorCode":null,"errorMessage":"Failed to install extension ${installMetadata.source}: ${result.errorMessage}","messagePattern":"Failed to install extension (.+?): (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/config/extension-manager.ts","lineNumber":280,"sourceCode":"          if (result.success) {\n            installMetadata.type = result.type;\n            installMetadata.releaseTag = result.tagName;\n          } else if (\n            // This repo has no github releases, and wasn't explicitly installed\n            // from a github release, unconditionally just clone it.\n            (result.failureReason === 'no release data' &&\n              installMetadata.type === 'git') ||\n            // Otherwise ask the user if they would like to try a git clone.\n            (await (requestConsentOverride ?? this.requestConsent)(\n              `Error downloading github release for ${installMetadata.source} with the following error: ${result.errorMessage}.\n\nWould you like to attempt to install via \"git clone\" instead?`,\n            ))\n          ) {\n            await cloneFromGit(installMetadata, tempDir);\n            installMetadata.type = 'git';\n          } else {\n            throw new Error(\n              `Failed to install extension ${installMetadata.source}: ${result.errorMessage}`,\n            );\n          }\n        }\n        localSourcePath = tempDir;\n      } else if (\n        installMetadata.type === 'local' ||\n        installMetadata.type === 'link'\n      ) {\n        localSourcePath = getRealPath(installMetadata.source);\n      } else {\n        throw new Error(`Unsupported install type: ${installMetadata.type}`);\n      }\n\n      try {\n        newExtensionConfig = await this.loadExtensionConfig(localSourcePath);\n\n        const newExtensionName = newExtensionConfig.name;","sourceCodeStart":262,"sourceCodeEnd":298,"githubUrl":"https://github.com/google-gemini/gemini-cli/blob/5024443c7217464a66e98f80d73172a26440bd8f/packages/cli/src/config/extension-manager.ts#L262-L298","documentation":"Thrown when downloading a github-release artifact fails AND the user declines (or is not asked for) the git-clone fallback. The wrapped message includes `result.errorMessage` from the download attempt (e.g. network error, 404, missing release). The error closes the install attempt without a fallback.","triggerScenarios":"The release download returns `success: false` for a reason other than `no release data` (e.g. rate limit, network failure, missing asset), and the consent prompt for git-clone fallback is declined; or `requestConsentOverride` returns false in a non-interactive run.","commonSituations":"GitHub API rate limits on unauthenticated installs; typos in the release tag; private repos without credentials; CI runners with no network egress to objects.githubusercontent.com; misconfigured proxies.","solutions":["Re-run with `--include-directories` / network access to GitHub and retry.","Set `GH_TOKEN` / `GITHUB_TOKEN` to authenticate and raise rate limits.","Accept the git-clone fallback at the prompt if the release simply has no assets.","Install directly from a git URL so `tryParseGithubUrl` is bypassed and `cloneFromGit` is used from the start."],"exampleFix":"// before\n$ gemini extensions install owner/repo@v1.0  # release download fails, decline clone\n// after\n$ GH_TOKEN=*** gemini extensions install owner/repo@v1.0  # accept clone fallback","handlingStrategy":"retry","validationCode":"function canReachGitHub(): Promise<boolean> {\n  return fetch('https://api.github.com', { method: 'HEAD' })\n    .then((r) => r.ok || r.status === 403)\n    .catch(() => false);\n}","typeGuard":"function isGithubRateLimited(msg: string): boolean {\n  return /rate limit/i.test(msg);\n}","tryCatchPattern":"try {\n  await installOrUpdateExtension(meta);\n} catch (e) {\n  if (/Failed to install extension/.test(getErrorMessage(e))) {\n    // retry with git clone path explicitly, or back off and retry after rate-limit reset\n    meta.type = 'git';\n    await installOrUpdateExtension(meta);\n  } else throw e;\n}","preventionTips":["Set `GH_TOKEN` / `GITHUB_TOKEN` to avoid unauthenticated rate limits.","Approach release-less repos via a plain git URL up front.","Verify network egress to `api.github.com` and `objects.githubusercontent.com` in CI."],"tags":["extensions","github","network","install"],"backgroundTag":null,"analyzedSha":"5024443c7217464a66e98f80d73172a26440bd8f","analyzedAt":"2026-08-12T06:01:53.711Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}