jackwener/OpenCLI · error · PluginError
Failed to clone plugin: ${getErrorMessage(err)}
Error message
Failed to clone plugin: ${getErrorMessage(err)} What it means
cloneRepoToTemp runs `git clone --depth 1 <url>` into a temp dir via execFileSync. If git exits non-zero (bad URL, auth failure, network outage, missing git binary), the error is wrapped in a PluginError with the underlying git message. opencli throws this because a plugin cannot be installed or updated without cloning its source repository.
Source
Thrown at src/plugin.ts:239
function createSiblingTempPath(dest: string, kind: 'tmp' | 'bak'): string {
const suffix = `${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`;
return path.join(path.dirname(dest), `.${path.basename(dest)}.${kind}-${suffix}`);
}
function cloneRepoToTemp(cloneUrl: string): string {
const tmpCloneDir = path.join(
os.tmpdir(),
`opencli-clone-${process.pid}-${Date.now()}-${Math.random().toString(16).slice(2)}`,
);
try {
execFileSync('git', ['clone', '--depth', '1', cloneUrl, tmpCloneDir], {
encoding: 'utf-8',
stdio: ['pipe', 'pipe', 'pipe'],
});
} catch (err) {
throw new PluginError(`Failed to clone plugin: ${getErrorMessage(err)}`, 'Check the repository URL and your network connection.');
}
return tmpCloneDir;
}
function withTempClone<T>(cloneUrl: string, work: (cloneDir: string) => T): T {
const tmpCloneDir = cloneRepoToTemp(cloneUrl);
try {
return work(tmpCloneDir);
} finally {
try { fs.rmSync(tmpCloneDir, { recursive: true, force: true }); } catch {}
}
}
function resolveRemotePluginSource(lockEntry: LockEntry | undefined, dir: string): string {
const source = resolvePluginSource(lockEntry, dir);
if (!source || source.kind === 'local') {
throw new Error(`Unable to determine remote source for plugin at ${dir}`);View on GitHub (pinned to 49907e53dc)
Solutions
- Verify the repository URL exists and is reachable: run `git ls-remote <cloneUrl>` manually.
- Check network/proxy/VPN; configure git proxy if needed (`git config --global http.proxy`).
- For private repos, set up credentials (SSH key, HTTPS token via credential helper) that match the URL scheme.
- Confirm git is installed and on PATH (`git --version`).
- Retry if the failure was transient (flaky network).
Example fix
// before
await installPlugin('github:user/typo-repo');
// after
await installPlugin('github:user/correct-repo'); // verified via git ls-remote Defensive patterns
Strategy: try-catch
Validate before calling
import { execFileSync } from 'node:child_process';
function canClone(url) {
try { execFileSync('git', ['ls-remote', url], { stdio: 'pipe' }); return true; }
catch { return false; }
} Try / catch
try {
installPlugin('github:user/repo');
} catch (err) {
if (err instanceof PluginError && err.message.startsWith('Failed to clone plugin')) {
// check URL/network, then retry
} else throw err;
} Prevention
- Verify repo URLs with `git ls-remote` before installing programmatically.
- Keep git installed and credentials (SSH keys / credential helper) configured.
- Check network/proxy reachability to the git host before batch installs.
When it happens
Trigger: installPlugin(source) or updatePlugin(name) with a git/monorepo source calls withTempClone -> cloneRepoToTemp; thrown when git clone fails: nonexistent repo, 404 on private repo without credentials, no network/DNS, proxy blocks github.com, or git is not installed.
Common situations: Typo in the GitHub user/repo; private repo with no SSH key or token; corporate firewall/proxy; offline laptop; git not on PATH (rare on dev machines); repo renamed or deleted.
Related errors
- npm install failed in ${dir}: ${getErrorMessage(err)}
- 12306 queryByTrainNo returned HTTP ${resp.status}
- 12306 queryByTrainNo returned non-JSON body
- 12306 ${endpoint} returned non-JSON body
- 12306 ${endpoint} returned an unexpected payload shape
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/71f44b540636bdd7.
Report an issue: GitHub.