{"record":{"id":"f3cca23c0f9041bb","repo":"mastra-ai/mastra","slug":"degit-completed-without-cloning-template-files-f3cca2","errorCode":null,"errorMessage":"degit completed without cloning template files","messagePattern":"degit completed without cloning template files","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/utils/clone-template.ts","lineNumber":105,"sourceCode":"  targetPath: string,\n  branch?: string,\n  signal?: AbortSignal,\n): Promise<void> {\n  signal?.throwIfAborted();\n\n  try {\n    // First try using degit if available (similar to Next.js)\n    const degitRepo = repoUrl.replace('https://github.com/', '');\n    // If branch is specified, append it to the degit repo (format: owner/repo#branch)\n    const degitRepoWithBranch = branch ? `${degitRepo}#${branch}` : degitRepo;\n    await execa('npx', ['degit', degitRepoWithBranch, targetPath], {\n      cwd: process.cwd(),\n      ...(signal ? { cancelSignal: signal } : {}),\n    });\n    signal?.throwIfAborted();\n\n    if ((await fs.readdir(targetPath)).length === 0) {\n      throw new Error('degit completed without cloning template files');\n    }\n  } catch {\n    if (signal?.aborted) signal.throwIfAborted();\n\n    // Degit can leave partial output behind, so reset only this clone-owned destination before the fallback.\n    await fs.rm(targetPath, { recursive: true, force: true });\n\n    // Fallback to git clone + remove .git\n    try {\n      const gitArgs = ['clone'];\n      // Add branch flag if specified\n      if (branch) {\n        gitArgs.push('--branch', branch);\n      }\n      gitArgs.push(repoUrl, targetPath);\n\n      await execa('git', gitArgs, {\n        cwd: process.cwd(),","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/cli/src/utils/clone-template.ts#L87-L123","documentation":"After degit (used by cloneRepositoryWithoutGit) exits without a thrown error, the code verifies the target directory is non-empty; if it is empty, degit silently failed (e.g. tarball download produced nothing), and this error is thrown. The catch block then removes the partial/empty destination before falling back to a plain git clone.","triggerScenarios":"cloneTemplate -> cloneRepositoryWithoutGit runs `degit` for the template's githubUrl; degit reports success but fs.readdir(targetPath) returns zero entries.","commonSituations":"Template repo renamed/moved so degit resolves nothing; network/proxy interference returning empty responses; degit cache corruption (~/.degit cache holding an empty or stale tarball); private/removed template repos.","solutions":["Retry — the code automatically falls back to `git clone` after cleaning the empty dir; a transient degit issue is usually bypassed.","Clear the degit cache (rm -rf ~/.degit) and retry.","Verify the template's githubUrl points to an existing, public, non-empty repository/branch."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// Pre-check: template source resolves and is non-empty\nconst res = await fetch(`https://api.github.com/repos/${owner}/${repo}`);\nif (!res.ok) throw new Error(`Template repo ${owner}/${repo} not accessible`);","typeGuard":null,"tryCatchPattern":"try {\n  await cloneTemplate(opts);\n} catch (err) {\n  if ((err as Error).message.includes('degit completed without cloning')) {\n    await fallbackGitClone(opts); // or retry with cleared ~/.degit cache\n  } else throw err;\n}","preventionTips":["Keep ~/.degit cache clean; clear it if clones come back empty.","Verify the template's githubUrl and branch exist and are public before scaffolding.","Prefer stable network connections; degit can silently fail behind proxies."],"tags":["network","degit","cloning","scaffolding"],"backgroundTag":"empty-clone-output","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}