mastra-ai/mastra · error

degit completed without cloning template files

Error message

degit completed without cloning template files

What it means

cloneTemplate first attempts to scaffold a template via `npx degit <repo> <target>`. degit can exit 0 while producing an empty directory (e.g. an invalid or renamed repo spec, network middleware issues, or degit's cache behaving badly), so the code treats an empty tempTarget as a failed clone and throws to fall back to `git clone`.

Source

Thrown at mastracode/mastra-factory/src/utils/clone.ts:57

export async function cloneTemplate(repoUrl: string, targetPath: string): Promise<void> {
  if (await pathExists(targetPath)) {
    throw new Error(`Directory ${path.basename(targetPath)} already exists`);
  }

  const tempRoot = await fs.mkdtemp(path.join(path.dirname(targetPath), `.${path.basename(targetPath)}-`));
  const tempTarget = path.join(tempRoot, 'template');

  try {
    try {
      const degitRepo = repoUrl.replace('https://github.com/', '');
      await x('npx', ['degit', degitRepo, tempTarget], {
        throwOnError: true,
        nodeOptions: { cwd: process.cwd() },
      });

      if ((await fs.readdir(tempTarget)).length === 0) {
        throw new Error('degit completed without cloning template files');
      }
    } catch {
      await fs.rm(tempTarget, { recursive: true, force: true });

      try {
        await x('git', ['clone', repoUrl, tempTarget], {
          throwOnError: true,
          nodeOptions: { cwd: process.cwd() },
        });

        const gitDir = path.join(tempTarget, '.git');
        if (await directoryExists(gitDir)) {
          await fs.rm(gitDir, { recursive: true, force: true });
        }
      } catch (gitError) {
        throw new Error(
          `Failed to clone repository: ${gitError instanceof Error ? gitError.message : 'Unknown error'}`,
        );

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Verify the degit repo spec (`owner/repo[#ref]`) points to a non-empty repo/ref, then retry
  2. Re-run with the network available (degit downloads a tarball; offline runs produce nothing)
  3. Clear degit's cache (~/.degit) if a stale cached entry is suspected
  4. Let the built-in fallback run: this throw triggers the git clone fallback path, so check that git is installed and the repo URL is reachable
  5. Clone the template manually with git to confirm it has content

Example fix

// before
await x('npx', ['degit', 'acme/renamed-template', tempTarget], { throwOnError: true });
// after
await x('npx', ['degit', 'acme/correct-template-name', tempTarget], { throwOnError: true });
Defensive patterns

Strategy: fallback

Validate before calling

const entries = await fs.readdir(templateDir);
if (entries.length === 0) throw new Error(`template ${repo} has no files`);

Type guard

null

Try / catch

try {
  await cloneTemplate(opts);
} catch (err) {
  if ((err as Error).message.includes('degit completed without cloning')) {
    // fall back to manual git clone
    await x('git', ['clone', repoUrl, target], { throwOnError: true });
  } else throw err;
}

Prevention

When it happens

Trigger: `cloneTemplate` runs `npx degit <repo> <target>` with throwOnError, then `fs.readdir(tempTarget)` returns 0 entries — degit exited successfully but wrote nothing (bad/renamed user/repo#ref spec, degit tarball fetch producing an empty extraction).

Common situations: Typo in the degit shorthand (e.g. 'user/nonexistent-repo' or wrong branch after a repo renamed its default branch), offline/proxy environments where degit silently no-ops, stale degit cache for a deleted ref, or a template repo that is genuinely empty.

Related errors


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