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
- Verify the degit repo spec (`owner/repo[#ref]`) points to a non-empty repo/ref, then retry
- Re-run with the network available (degit downloads a tarball; offline runs produce nothing)
- Clear degit's cache (~/.degit) if a stale cached entry is suspected
- 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
- 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
- Verify the degit spec with `npx degit --dry-run` style checks or `git ls-remote`
- Confirm the template repo/ref is non-empty before scaffolding
- Keep the git-clone fallback path available (git installed)
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
- Token exchange failed: ${error}
- Failed to fetch user info from Auth0
- Token exchange failed: ${error}
- Failed to fetch user info from Clerk
- Google token exchange failed: ${error}
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/e9082b14651d4b63.
Report an issue: GitHub.