vercel-labs/skills · error · GitCloneError
buildGitHubAuthError(url, repo, errorMessage)
Error message
buildGitHubAuthError(url, repo, errorMessage)
What it means
When a clone fails and the error text matches auth-failure heuristics (isAuthFailure), cloneRepo throws a GitCloneError whose message is built by buildGitHubAuthError — a detailed guide covering SSH key and HTTPS/gh credential setup for private repositories.
Source
Thrown at src/git.ts:294
}
try {
await resetTempDir(tempDir);
await createGitClient(process.env.GIT_SSH_COMMAND ?? 'ssh -o BatchMode=yes').clone(
repo.sshUrl,
tempDir,
cloneOptions
);
return tempDir;
} catch {
// Fall through to the targeted auth error below.
}
}
await rm(tempDir, { recursive: true, force: true }).catch(() => {});
if (isAuthError) {
throw new GitCloneError(buildGitHubAuthError(url, repo, errorMessage), url, false, true);
}
throw new GitCloneError(`Failed to clone ${url}: ${errorMessage}`, url, false, false);
}
}
/**
* Resolve the Git tree object for a locked skill path in a cloned repository.
* This matches the folder SHA returned by GitHub's Trees API.
*/
export async function getGitTreeHash(repoDir: string, skillPath: string): Promise<string | null> {
const normalizedPath = skillPath.replace(/\\/g, '/');
const segments = normalizedPath.split('/');
segments.pop();
const folderPath = segments.join('/');
const revision = folderPath ? `HEAD:${folderPath}` : 'HEAD^{tree}';
try {View on GitHub (pinned to 435076e789)
Solutions
- For HTTPS: run gh auth login (or export GH_TOKEN/GITHUB_TOKEN with repo scope)
- For SSH: verify ssh-add -l lists a key and ssh -T git@github.com authenticates
- If using a PAT, confirm it is not expired and has access to the specific private org/repo (SSO authorized)
- Alternatively clone where credentials already work and 'skills add <local-path>'
Example fix
# before skills add github.com/org/private-skills # auth failure # after gh auth login skills add github.com/org/private-skills
Defensive patterns
Strategy: fallback
Validate before calling
async function canClone(url: string): Promise<boolean> {
try {
execSync(`git ls-remote ${JSON.stringify(url)} HEAD`, { stdio: 'ignore', timeout: 20000 });
return true;
} catch { return false; }
} Type guard
function isGitAuthError(e: unknown): e is Error {
return e instanceof Error && /Permission to|authentication|credentials|gh auth|publickey/i.test(e.message);
} Try / catch
try { await cloneRepo(url); }
catch (e) {
if (isGitAuthError(e)) {
notifyUser('Run `gh auth login` or load an SSH key, then retry');
return; // user-actionable, don't crash the process
}
throw e;
} Prevention
- Run gh auth login (or export GH_TOKEN) in CI before skill installs
- Verify ssh -T git@github.com works for SSH workflows
- Keep tokens fresh; org SSO re-authorization expires silently
When it happens
Trigger: Cloning a private GitHub repo with missing/invalid credentials: no SSH key loaded (Permission denied (publickey)), expired gh token, revoked PAT, or HTTPS 403/Authentication failed output from git.
Common situations: Fresh machines without gh auth login; SSH keys not added to the agent; organization SSO tokens that expired; CI jobs missing the GITHUB_TOKEN/GH_TOKEN secret.
Related errors
- Unsupported Git transport: ext
- Clone timed out after ${seconds}s. Common causes: - Large
- Failed to clone ${url}: ${errorMessage}
AI-assisted analysis of vercel-labs/skills@435076e789 (2026-08-28).
Data as JSON: /api/errors/c268e7df500cf67d.
Report an issue: GitHub.