mastra-ai/mastra · error

Directory ${path.basename(targetPath)} already exists

Error message

Directory ${path.basename(targetPath)} already exists

What it means

cloneTemplate clones the template repository into targetPath via a temp directory. Before doing any work it checks pathExists(targetPath); if a directory (or file) already exists at the destination, it throws immediately instead of overwriting user data — a deliberate safety guard.

Source

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

    await fs.access(filePath);
    return true;
  } catch (error) {
    if ((error as NodeJS.ErrnoException).code === 'ENOENT') return false;
    throw error;
  }
}

async function directoryExists(dirPath: string): Promise<boolean> {
  try {
    return (await fs.stat(dirPath)).isDirectory();
  } catch {
    return false;
  }
}

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 });

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Choose a new targetPath or rename/remove the existing directory, then rerun.
  2. Inspect the existing directory first — if it's a leftover failed run, delete it manually (also clean sibling `.target-*` temp dirs).
  3. Rerun inside a different, empty parent directory.
  4. If the existing directory is empty and safe, delete it with `rm -rf <dir>` before re-running.

Example fix

// before
$ create-factory ./my-app
// Error: Directory my-app already exists
// after
$ rm -rf ./my-app            # or: mv ./my-app ./my-app.bak
$ create-factory ./my-app
Defensive patterns

Strategy: validation

Validate before calling

import { pathExists } from './utils/clone';
if (await pathExists(targetPath)) {
  const alt = `${targetPath}-${Date.now()}`;
  console.warn(`'${targetPath}' exists — using '${alt}' instead.`);
  targetPath = alt;
}
await cloneTemplate(repoUrl, targetPath);

Try / catch

try {
  await cloneTemplate(repoUrl, targetPath);
} catch (err) {
  if (err.message.includes('already exists')) {
    const backup = `${targetPath}.bak-${Date.now()}`;
    await fs.rename(targetPath, backup);
    console.log(`Moved existing directory to ${backup}; retrying clone.`);
    await cloneTemplate(repoUrl, targetPath);
  } else throw err;
}

Prevention

When it happens

Trigger: Running `create-factory` (or cloneTemplate) with a targetPath that already exists on disk — e.g. a previous partial/complete scaffold, or an unrelated directory at that path.

Common situations: Re-running the scaffold command in the same folder after an earlier run; a crashed previous run left a `.target-` temp dir plus a recreated target; user pre-created the project folder (e.g. via mkdir or git clone); IDE-generated folders occupying the name.

Related errors


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