{"record":{"id":"3b0e3d62a765c20e","repo":"vercel-labs/skills","slug":"clone-timed-out-after-seconds-s-common-causes","errorCode":null,"errorMessage":"Clone timed out after ${seconds}s. Common causes:\n  - Large repository: raise the timeout with SKILLS_CLONE_TIMEOUT_MS=600000 (10m)\n  - Slow network: retry, or clone manually and pass the local path to 'skills add'\n  - Private repo without credentials: ensure auth is configured\n      - For SSH: ssh-add -l (to check loaded keys)\n      - For HTTPS: gh auth status (if using GitHub CLI)","messagePattern":"Clone timed out after (.+?)s\\. Common causes:\n  - Large repository: raise the timeout with SKILLS_CLONE_TIMEOUT_MS=600000 \\(10m\\)\n  - Slow network: retry, or clone manually and pass the local path to 'skills add'\n  - Private repo without credentials: ensure auth is configured\n      - For SSH: ssh-add -l \\(to check loaded keys\\)\n      - For HTTPS: gh auth status \\(if using GitHub CLI\\)","errorType":"exception","errorClass":"GitCloneError","httpStatus":null,"severity":"error","filePath":"src/git.ts","lineNumber":255,"sourceCode":"    throw new GitCloneError('Unsupported Git transport: ext', url);\n  }\n\n  const tempDir = await mkdtemp(join(tmpdir(), 'skills-'));\n  const cloneOptions = ref ? ['--depth', '1', '--branch', ref] : ['--depth', '1'];\n  const repo = parseGitHubRepoUrl(url);\n\n  try {\n    await createGitClient().clone(url, tempDir, cloneOptions);\n    return tempDir;\n  } catch (error) {\n    const errorMessage = error instanceof Error ? error.message : String(error);\n    const isTimeout = errorMessage.includes('block timeout') || errorMessage.includes('timed out');\n    const isAuthError = isAuthFailure(errorMessage);\n\n    if (isTimeout) {\n      await rm(tempDir, { recursive: true, force: true }).catch(() => {});\n      const seconds = Math.round(CLONE_TIMEOUT_MS / 1000);\n      throw new GitCloneError(\n        `Clone timed out after ${seconds}s. Common causes:\\n` +\n          `  - Large repository: raise the timeout with SKILLS_CLONE_TIMEOUT_MS=600000 (10m)\\n` +\n          `  - Slow network: retry, or clone manually and pass the local path to 'skills add'\\n` +\n          `  - Private repo without credentials: ensure auth is configured\\n` +\n          `      - For SSH: ssh-add -l (to check loaded keys)\\n` +\n          `      - For HTTPS: gh auth status (if using GitHub CLI)`,\n        url,\n        true,\n        false\n      );\n    }\n\n    if (isAuthError && repo && isGitHubHttpsCloneUrl(url)) {\n      try {\n        await resetTempDir(tempDir);\n        if (await tryGhClone(repo, tempDir, ref)) {\n          return tempDir;\n        }","sourceCodeStart":237,"sourceCodeEnd":273,"githubUrl":"https://github.com/vercel-labs/skills/blob/435076e78988e1e6ec40d00b0b1d76bdbbc5419a/src/git.ts#L237-L273","documentation":"cloneRepo() enforces a global clone timeout (CLONE_TIMEOUT_MS, configurable via SKILLS_CLONE_TIMEOUT_MS). When the underlying git process fails with a timeout/blocked-timeout message, the temp clone dir is removed and this GitCloneError with remediation hints is thrown.","triggerScenarios":"A 'git clone --depth 1' exceeding CLONE_TIMEOUT_MS — typically monorepos with large history or LFS objects, very slow networks, or a private repo silently hanging on credential prompts.","commonSituations":"Adding big skill monorepos over slow links; CI runners with constrained egress; SSH keys not loaded so git blocks on passphrase/auth until timeout.","solutions":["Raise the limit: SKILLS_CLONE_TIMEOUT_MS=600000 skills add <repo>","Check credentials so git doesn't stall: ssh-add -l for SSH, gh auth status for HTTPS","Retry on a better network, or clone manually and pass the local path: git clone <url> /tmp/r && skills add /tmp/r","If it's a huge monorepo, clone with sparse checkout yourself and add the local path"],"exampleFix":"# before\nskills add github.com/org/huge-monorepo   # times out\n# after\nSKILLS_CLONE_TIMEOUT_MS=600000 skills add github.com/org/huge-monorepo","handlingStrategy":"retry","validationCode":"import { execSync } from 'node:child_process';\nfunction repoLikelyCloneable(url: string): boolean {\n  try { execSync(`git ls-remote --heads ${JSON.stringify(url)}`, { timeout: 15000, stdio: 'ignore' }); return true; }\n  catch { return false; }\n}","typeGuard":"function isCloneTimeout(e: unknown): e is Error {\n  return e instanceof Error && /Clone timed out/i.test(e.message);\n}","tryCatchPattern":"try { await cloneRepo(url); }\ncatch (e) {\n  if (isCloneTimeout(e)) {\n    process.env.SKILLS_CLONE_TIMEOUT_MS = '600000';\n    return await cloneRepo(url); // one retry with raised timeout\n  }\n  throw e;\n}","preventionTips":["Pre-flight with git ls-remote to gauge reachability","Set SKILLS_CLONE_TIMEOUT_MS higher for known-large repos","Ensure credentials are configured so git never blocks on prompts"],"tags":["git","timeout","clone","network"],"backgroundTag":"git-clone-timeout","analyzedSha":"435076e78988e1e6ec40d00b0b1d76bdbbc5419a","analyzedAt":"2026-08-28T17:47:53.369Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}