mastra-ai/mastra · error · Error

degit completed without cloning template files

Error message

degit completed without cloning template files

What it means

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.

Source

Thrown at packages/cli/src/utils/clone-template.ts:105

  targetPath: string,
  branch?: string,
  signal?: AbortSignal,
): Promise<void> {
  signal?.throwIfAborted();

  try {
    // First try using degit if available (similar to Next.js)
    const degitRepo = repoUrl.replace('https://github.com/', '');
    // If branch is specified, append it to the degit repo (format: owner/repo#branch)
    const degitRepoWithBranch = branch ? `${degitRepo}#${branch}` : degitRepo;
    await execa('npx', ['degit', degitRepoWithBranch, targetPath], {
      cwd: process.cwd(),
      ...(signal ? { cancelSignal: signal } : {}),
    });
    signal?.throwIfAborted();

    if ((await fs.readdir(targetPath)).length === 0) {
      throw new Error('degit completed without cloning template files');
    }
  } catch {
    if (signal?.aborted) signal.throwIfAborted();

    // Degit can leave partial output behind, so reset only this clone-owned destination before the fallback.
    await fs.rm(targetPath, { recursive: true, force: true });

    // Fallback to git clone + remove .git
    try {
      const gitArgs = ['clone'];
      // Add branch flag if specified
      if (branch) {
        gitArgs.push('--branch', branch);
      }
      gitArgs.push(repoUrl, targetPath);

      await execa('git', gitArgs, {
        cwd: process.cwd(),

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Retry — the code automatically falls back to `git clone` after cleaning the empty dir; a transient degit issue is usually bypassed.
  2. Clear the degit cache (rm -rf ~/.degit) and retry.
  3. Verify the template's githubUrl points to an existing, public, non-empty repository/branch.
Defensive patterns

Strategy: fallback

Validate before calling

// Pre-check: template source resolves and is non-empty
const res = await fetch(`https://api.github.com/repos/${owner}/${repo}`);
if (!res.ok) throw new Error(`Template repo ${owner}/${repo} not accessible`);

Try / catch

try {
  await cloneTemplate(opts);
} catch (err) {
  if ((err as Error).message.includes('degit completed without cloning')) {
    await fallbackGitClone(opts); // or retry with cleared ~/.degit cache
  } else throw err;
}

Prevention

When it happens

Trigger: cloneTemplate -> cloneRepositoryWithoutGit runs `degit` for the template's githubUrl; degit reports success but fs.readdir(targetPath) returns zero entries.

Common situations: 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.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/f3cca23c0f9041bb. Report an issue: GitHub.