vercel-labs/skills · error · GitCloneError

Failed to clone ${url}: ${errorMessage}

Error message

Failed to clone ${url}: ${errorMessage}

What it means

The generic clone failure in cloneRepo(): git exited non-zero, it was neither a timeout nor an auth error, so the raw git stderr is wrapped: 'Failed to clone <url>: <message>'. The temp directory is cleaned up before throwing.

Source

Thrown at src/git.ts:297

        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 {
    const stdout = await new Promise<string>((resolve, reject) => {
      execFile(
        'git',

View on GitHub (pinned to 435076e789)

Solutions

  1. Copy the git stderr from the message and reproduce manually: git clone --depth 1 <url> to see the full failure
  2. Fix the URL/branch: verify the repo exists in a browser and the branch name is correct
  3. If DNS/proxy: configure https.proxy or correct corporate proxy env vars
  4. If repo is private, see auth errors — sometimes 404 masks missing credentials

Example fix

# before (branch typo)
skills add github.com/org/repo --ref maain
# after
skills add github.com/org/repo --ref main
Defensive patterns

Strategy: try-catch

Validate before calling

const exists = await fetch(`https://api.github.com/repos/${owner}/${repo}`, {
  headers: token ? { Authorization: `Bearer ${token}` } : {},
}).then((r) => r.ok);
if (!exists) throw new Error(`Repo ${owner}/${repo} not reachable; check spelling/visibility`);

Type guard

function isGitCloneError(e: unknown): e is Error {
  return e instanceof Error && /^Failed to clone /.test(e.message);
}

Try / catch

try { await cloneRepo(url, ref); }
catch (e) {
  if (isGitCloneError(e)) {
    logger.error(e.message); // contains raw git stderr for diagnosis
    return fallbackToLocalMirror(url);
  }
  throw e;
}

Prevention

When it happens

Trigger: Any non-timeout, non-auth git failure: repository not found (HTTPS 404 on public repo), invalid ref/branch name, malformed URL, DNS failure ('Could not resolve host'), disk full, or unsupported git protocol.

Common situations: Typos in owner/repo shorthand; deleted or renamed repositories; branch specified doesn't exist; corporate proxies blocking git:// protocol; old git versions lacking needed features.

Related errors


AI-assisted analysis of vercel-labs/skills@435076e789 (2026-08-28). Data as JSON: /api/errors/bbcdab24392f5ca7. Report an issue: GitHub.